terser 5.16.4 → 5.16.6

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,16 @@
1
1
  # Changelog
2
2
 
3
+ ## v5.16.7
4
+
5
+ - Become less conservative with analyzing function definitions for `reduce_vars`
6
+ - Parse `import.meta` as a real AST node and not an `object.property`
7
+
8
+ ## v5.16.5
9
+
10
+ - Correctly handle AST transform functions that mutate children arrays
11
+ - Don't mutate the options object passed to Terser (#1342)
12
+ - Do not treat BigInt like a number
13
+
3
14
  ## v5.16.4
4
15
 
5
16
  - Keep `(defaultArg = undefined) => ...`, because default args don't count for function length
@@ -101,36 +101,20 @@ function return_null() { return null; }
101
101
 
102
102
  var MAP = (function() {
103
103
  function MAP(a, tw, allow_splicing = true) {
104
- // Loop but try not to build a new array
104
+ const new_a = [];
105
+
105
106
  for (let i = 0; i < a.length; ++i) {
106
107
  let item = a[i];
107
108
  let ret = item.transform(tw, allow_splicing);
108
109
 
109
- if (ret !== item) {
110
- const a1 = a.slice(0, i);
111
-
112
- // Looks like something was transformed. Change the loop.
113
- if (ret instanceof AST_Node) {
114
- a1.push(ret);
115
- } else if (ret instanceof Splice) {
116
- a1.push(...ret.v);
117
- }
118
-
119
- while ((item = a[++i])) {
120
- const ret = item.transform(tw, true);
121
-
122
- if (ret instanceof AST_Node) {
123
- a1.push(ret);
124
- } else if (ret instanceof Splice) {
125
- a1.push(...ret.v);
126
- }
127
- }
128
-
129
- return a1;
110
+ if (ret instanceof AST_Node) {
111
+ new_a.push(ret);
112
+ } else if (ret instanceof Splice) {
113
+ new_a.push(...ret.v);
130
114
  }
131
115
  }
132
116
 
133
- return a;
117
+ return new_a;
134
118
  }
135
119
 
136
120
  MAP.splice = function(val) { return new Splice(val); };
@@ -2466,7 +2450,7 @@ function parse($TEXT, options) {
2466
2450
  if (is("operator", "new")) {
2467
2451
  return new_(allow_calls);
2468
2452
  }
2469
- if (is("operator", "import")) {
2453
+ if (is("name", "import") && is_token(peek(), "punc", ".")) {
2470
2454
  return import_meta();
2471
2455
  }
2472
2456
  var start = S.token;
@@ -2962,7 +2946,7 @@ function parse($TEXT, options) {
2962
2946
 
2963
2947
  function import_meta() {
2964
2948
  var start = S.token;
2965
- expect_token("operator", "import");
2949
+ expect_token("name", "import");
2966
2950
  expect_token("punc", ".");
2967
2951
  expect_token("name", "meta");
2968
2952
  return subscripts(new AST_ImportMeta({
@@ -3866,8 +3850,21 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", function AST_Simple
3866
3850
 
3867
3851
  function walk_body(node, visitor) {
3868
3852
  const body = node.body;
3869
- for (var i = 0, len = body.length; i < len; i++) {
3870
- body[i]._walk(visitor);
3853
+ if (visitor.walk_defun_first) {
3854
+ for (var i = 0, len = body.length; i < len; i++) {
3855
+ if (body[i] instanceof AST_Defun) {
3856
+ body[i]._walk(visitor);
3857
+ }
3858
+ }
3859
+ for (var i = 0, len = body.length; i < len; i++) {
3860
+ if (!(body[i] instanceof AST_Defun)) {
3861
+ body[i]._walk(visitor);
3862
+ }
3863
+ }
3864
+ } else {
3865
+ for (var i = 0, len = body.length; i < len; i++) {
3866
+ body[i]._walk(visitor);
3867
+ }
3871
3868
  }
3872
3869
  }
3873
3870
 
@@ -6646,10 +6643,11 @@ const walk_abort = Symbol("abort walk");
6646
6643
  /* -----[ TreeWalker ]----- */
6647
6644
 
6648
6645
  class TreeWalker {
6649
- constructor(callback) {
6646
+ constructor(callback, { walk_defun_first = false } = {}) {
6650
6647
  this.visit = callback;
6651
6648
  this.stack = [];
6652
6649
  this.directives = Object.create(null);
6650
+ this.walk_defun_first = walk_defun_first;
6653
6651
  }
6654
6652
 
6655
6653
  _visit(node, descend) {
@@ -13367,7 +13365,7 @@ const unary_side_effects = makePredicate("delete ++ --");
13367
13365
  def_is_number(AST_Number, return_true);
13368
13366
  const unary = makePredicate("+ - ~ ++ --");
13369
13367
  def_is_number(AST_Unary, function() {
13370
- return unary.has(this.operator);
13368
+ return unary.has(this.operator) && !(this.expression instanceof AST_BigInt);
13371
13369
  });
13372
13370
  const numeric_ops = makePredicate("- * / % & | ^ << >> >>>");
13373
13371
  def_is_number(AST_Binary, function(compressor) {
@@ -13505,6 +13503,7 @@ function is_nullish(node, compressor) {
13505
13503
  || this.body && this.body.has_side_effects(compressor)
13506
13504
  || this.alternative && this.alternative.has_side_effects(compressor);
13507
13505
  });
13506
+ def_has_side_effects(AST_ImportMeta, return_false);
13508
13507
  def_has_side_effects(AST_LabeledStatement, function(compressor) {
13509
13508
  return this.body.has_side_effects(compressor);
13510
13509
  });
@@ -13608,6 +13607,7 @@ function is_nullish(node, compressor) {
13608
13607
  def_may_throw(AST_Lambda, return_false);
13609
13608
  def_may_throw(AST_SymbolDeclaration, return_false);
13610
13609
  def_may_throw(AST_This, return_false);
13610
+ def_may_throw(AST_ImportMeta, return_false);
13611
13611
 
13612
13612
  function any(list, compressor) {
13613
13613
  for (var i = list.length; --i >= 0;)
@@ -13971,6 +13971,11 @@ function is_lhs(node, parent) {
13971
13971
  var name = this.name + suffix;
13972
13972
  if (HOP(defines, name)) return to_node(defines[name], this);
13973
13973
  });
13974
+ def_find_defs(AST_ImportMeta, function(compressor, suffix) {
13975
+ var defines = compressor.option("global_defs");
13976
+ var name = "import.meta" + suffix;
13977
+ if (HOP(defines, name)) return to_node(defines[name], this);
13978
+ });
13974
13979
  })(function(node, func) {
13975
13980
  node.DEFMETHOD("_find_defs", func);
13976
13981
  });
@@ -15719,15 +15724,7 @@ def_reduce_vars(AST_Default, function(tw, descend) {
15719
15724
  function mark_lambda(tw, descend, compressor) {
15720
15725
  clear_flag(this, INLINED);
15721
15726
 
15722
- // Sometimes we detach the lambda for safety, and instead of push()
15723
- // we go to an entirely fresh lineage of safe_ids.
15724
- let previous_safe_ids;
15725
- if (this instanceof AST_Defun || this.uses_arguments || this.pinned()) {
15726
- previous_safe_ids = tw.safe_ids;
15727
- tw.safe_ids = Object.create(null);
15728
- } else {
15729
- push(tw);
15730
- }
15727
+ push(tw);
15731
15728
 
15732
15729
  reset_variables(tw, compressor, this);
15733
15730
 
@@ -15759,13 +15756,9 @@ function mark_lambda(tw, descend, compressor) {
15759
15756
  }
15760
15757
  });
15761
15758
  }
15762
- descend();
15763
15759
 
15764
- if (previous_safe_ids) {
15765
- tw.safe_ids = previous_safe_ids;
15766
- } else {
15767
- pop(tw);
15768
- }
15760
+ descend();
15761
+ pop(tw);
15769
15762
 
15770
15763
  return true;
15771
15764
  }
@@ -18265,7 +18258,7 @@ AST_Toplevel.DEFMETHOD("reset_opt_flags", function(compressor) {
18265
18258
  }
18266
18259
  return node.reduce_vars(preparation, descend, compressor);
18267
18260
  }
18268
- });
18261
+ }, { walk_defun_first: true });
18269
18262
  // Stack of look-up tables to keep track of whether a `SymbolDef` has been
18270
18263
  // properly assigned before use:
18271
18264
  // - `push()` & `pop()` when visiting conditional branches
@@ -30011,10 +30004,13 @@ async function minify(files, options, _fs_module) {
30011
30004
  if (options.format.spidermonkey) {
30012
30005
  result.ast = toplevel.to_mozilla_ast();
30013
30006
  }
30007
+ let format_options;
30014
30008
  if (!HOP(options.format, "code") || options.format.code) {
30015
- if (!options.format.ast) {
30009
+ // Make a shallow copy so that we can modify without mutating the user's input.
30010
+ format_options = {...options.format};
30011
+ if (!format_options.ast) {
30016
30012
  // Destroy stuff to save RAM. (unless the deprecated `ast` option is on)
30017
- options.format._destroy_ast = true;
30013
+ format_options._destroy_ast = true;
30018
30014
 
30019
30015
  walk(toplevel, node => {
30020
30016
  if (node instanceof AST_Scope) {
@@ -30034,17 +30030,17 @@ async function minify(files, options, _fs_module) {
30034
30030
  if (options.sourceMap.includeSources && files instanceof AST_Toplevel) {
30035
30031
  throw new Error("original source content unavailable");
30036
30032
  }
30037
- options.format.source_map = await SourceMap({
30033
+ format_options.source_map = await SourceMap({
30038
30034
  file: options.sourceMap.filename,
30039
30035
  orig: options.sourceMap.content,
30040
30036
  root: options.sourceMap.root,
30041
30037
  files: options.sourceMap.includeSources ? files : null,
30042
30038
  });
30043
30039
  }
30044
- delete options.format.ast;
30045
- delete options.format.code;
30046
- delete options.format.spidermonkey;
30047
- var stream = OutputStream(options.format);
30040
+ delete format_options.ast;
30041
+ delete format_options.code;
30042
+ delete format_options.spidermonkey;
30043
+ var stream = OutputStream(format_options);
30048
30044
  toplevel.print(stream);
30049
30045
  result.code = stream.get();
30050
30046
  if (options.sourceMap) {
@@ -30052,7 +30048,7 @@ async function minify(files, options, _fs_module) {
30052
30048
  configurable: true,
30053
30049
  enumerable: true,
30054
30050
  get() {
30055
- const map = options.format.source_map.getEncoded();
30051
+ const map = format_options.source_map.getEncoded();
30056
30052
  return (result.map = options.sourceMap.asObject ? map : JSON.stringify(map));
30057
30053
  },
30058
30054
  set(value) {
@@ -30062,7 +30058,7 @@ async function minify(files, options, _fs_module) {
30062
30058
  });
30063
30059
  }
30064
30060
  });
30065
- result.decoded_map = options.format.source_map.getDecoded();
30061
+ result.decoded_map = format_options.source_map.getDecoded();
30066
30062
  if (options.sourceMap.url == "inline") {
30067
30063
  var sourceMap = typeof result.map === "object" ? JSON.stringify(result.map) : result.map;
30068
30064
  result.code += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + to_base64(sourceMap);
@@ -30077,8 +30073,8 @@ async function minify(files, options, _fs_module) {
30077
30073
  options.nameCache.props = cache_to_json(options.mangle.properties.cache);
30078
30074
  }
30079
30075
  }
30080
- if (options.format && options.format.source_map) {
30081
- options.format.source_map.destroy();
30076
+ if (format_options && format_options.source_map) {
30077
+ format_options.source_map.destroy();
30082
30078
  }
30083
30079
  if (timings) {
30084
30080
  timings.end = Date.now();
package/lib/ast.js CHANGED
@@ -249,8 +249,21 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", function AST_Simple
249
249
 
250
250
  function walk_body(node, visitor) {
251
251
  const body = node.body;
252
- for (var i = 0, len = body.length; i < len; i++) {
253
- body[i]._walk(visitor);
252
+ if (visitor.walk_defun_first) {
253
+ for (var i = 0, len = body.length; i < len; i++) {
254
+ if (body[i] instanceof AST_Defun) {
255
+ body[i]._walk(visitor);
256
+ }
257
+ }
258
+ for (var i = 0, len = body.length; i < len; i++) {
259
+ if (!(body[i] instanceof AST_Defun)) {
260
+ body[i]._walk(visitor);
261
+ }
262
+ }
263
+ } else {
264
+ for (var i = 0, len = body.length; i < len; i++) {
265
+ body[i]._walk(visitor);
266
+ }
254
267
  }
255
268
  }
256
269
 
@@ -3029,10 +3042,11 @@ const walk_abort = Symbol("abort walk");
3029
3042
  /* -----[ TreeWalker ]----- */
3030
3043
 
3031
3044
  class TreeWalker {
3032
- constructor(callback) {
3045
+ constructor(callback, { walk_defun_first = false } = {}) {
3033
3046
  this.visit = callback;
3034
3047
  this.stack = [];
3035
3048
  this.directives = Object.create(null);
3049
+ this.walk_defun_first = walk_defun_first;
3036
3050
  }
3037
3051
 
3038
3052
  _visit(node, descend) {
@@ -539,7 +539,7 @@ AST_Toplevel.DEFMETHOD("reset_opt_flags", function(compressor) {
539
539
  }
540
540
  return node.reduce_vars(preparation, descend, compressor);
541
541
  }
542
- });
542
+ }, { walk_defun_first: true });
543
543
  // Stack of look-up tables to keep track of whether a `SymbolDef` has been
544
544
  // properly assigned before use:
545
545
  // - `push()` & `pop()` when visiting conditional branches
@@ -45,6 +45,7 @@ import {
45
45
  AST_Array,
46
46
  AST_Arrow,
47
47
  AST_Assign,
48
+ AST_BigInt,
48
49
  AST_Binary,
49
50
  AST_Block,
50
51
  AST_BlockStatement,
@@ -66,6 +67,7 @@ import {
66
67
  AST_Function,
67
68
  AST_If,
68
69
  AST_Import,
70
+ AST_ImportMeta,
69
71
  AST_Jump,
70
72
  AST_LabeledStatement,
71
73
  AST_Lambda,
@@ -171,7 +173,7 @@ export const unary_side_effects = makePredicate("delete ++ --");
171
173
  def_is_number(AST_Number, return_true);
172
174
  const unary = makePredicate("+ - ~ ++ --");
173
175
  def_is_number(AST_Unary, function() {
174
- return unary.has(this.operator);
176
+ return unary.has(this.operator) && !(this.expression instanceof AST_BigInt);
175
177
  });
176
178
  const numeric_ops = makePredicate("- * / % & | ^ << >> >>>");
177
179
  def_is_number(AST_Binary, function(compressor) {
@@ -309,6 +311,7 @@ export function is_nullish(node, compressor) {
309
311
  || this.body && this.body.has_side_effects(compressor)
310
312
  || this.alternative && this.alternative.has_side_effects(compressor);
311
313
  });
314
+ def_has_side_effects(AST_ImportMeta, return_false);
312
315
  def_has_side_effects(AST_LabeledStatement, function(compressor) {
313
316
  return this.body.has_side_effects(compressor);
314
317
  });
@@ -412,6 +415,7 @@ export function is_nullish(node, compressor) {
412
415
  def_may_throw(AST_Lambda, return_false);
413
416
  def_may_throw(AST_SymbolDeclaration, return_false);
414
417
  def_may_throw(AST_This, return_false);
418
+ def_may_throw(AST_ImportMeta, return_false);
415
419
 
416
420
  function any(list, compressor) {
417
421
  for (var i = list.length; --i >= 0;)
@@ -775,6 +779,11 @@ export function is_lhs(node, parent) {
775
779
  var name = this.name + suffix;
776
780
  if (HOP(defines, name)) return to_node(defines[name], this);
777
781
  });
782
+ def_find_defs(AST_ImportMeta, function(compressor, suffix) {
783
+ var defines = compressor.option("global_defs");
784
+ var name = "import.meta" + suffix;
785
+ if (HOP(defines, name)) return to_node(defines[name], this);
786
+ });
778
787
  })(function(node, func) {
779
788
  node.DEFMETHOD("_find_defs", func);
780
789
  });
@@ -448,15 +448,7 @@ def_reduce_vars(AST_Default, function(tw, descend) {
448
448
  function mark_lambda(tw, descend, compressor) {
449
449
  clear_flag(this, INLINED);
450
450
 
451
- // Sometimes we detach the lambda for safety, and instead of push()
452
- // we go to an entirely fresh lineage of safe_ids.
453
- let previous_safe_ids;
454
- if (this instanceof AST_Defun || this.uses_arguments || this.pinned()) {
455
- previous_safe_ids = tw.safe_ids;
456
- tw.safe_ids = Object.create(null);
457
- } else {
458
- push(tw);
459
- }
451
+ push(tw);
460
452
 
461
453
  reset_variables(tw, compressor, this);
462
454
 
@@ -488,13 +480,9 @@ function mark_lambda(tw, descend, compressor) {
488
480
  }
489
481
  });
490
482
  }
491
- descend();
492
483
 
493
- if (previous_safe_ids) {
494
- tw.safe_ids = previous_safe_ids;
495
- } else {
496
- pop(tw);
497
- }
484
+ descend();
485
+ pop(tw);
498
486
 
499
487
  return true;
500
488
  }
package/lib/minify.js CHANGED
@@ -280,10 +280,13 @@ async function minify(files, options, _fs_module) {
280
280
  if (options.format.spidermonkey) {
281
281
  result.ast = toplevel.to_mozilla_ast();
282
282
  }
283
+ let format_options;
283
284
  if (!HOP(options.format, "code") || options.format.code) {
284
- if (!options.format.ast) {
285
+ // Make a shallow copy so that we can modify without mutating the user's input.
286
+ format_options = {...options.format};
287
+ if (!format_options.ast) {
285
288
  // Destroy stuff to save RAM. (unless the deprecated `ast` option is on)
286
- options.format._destroy_ast = true;
289
+ format_options._destroy_ast = true;
287
290
 
288
291
  walk(toplevel, node => {
289
292
  if (node instanceof AST_Scope) {
@@ -303,17 +306,17 @@ async function minify(files, options, _fs_module) {
303
306
  if (options.sourceMap.includeSources && files instanceof AST_Toplevel) {
304
307
  throw new Error("original source content unavailable");
305
308
  }
306
- options.format.source_map = await SourceMap({
309
+ format_options.source_map = await SourceMap({
307
310
  file: options.sourceMap.filename,
308
311
  orig: options.sourceMap.content,
309
312
  root: options.sourceMap.root,
310
313
  files: options.sourceMap.includeSources ? files : null,
311
314
  });
312
315
  }
313
- delete options.format.ast;
314
- delete options.format.code;
315
- delete options.format.spidermonkey;
316
- var stream = OutputStream(options.format);
316
+ delete format_options.ast;
317
+ delete format_options.code;
318
+ delete format_options.spidermonkey;
319
+ var stream = OutputStream(format_options);
317
320
  toplevel.print(stream);
318
321
  result.code = stream.get();
319
322
  if (options.sourceMap) {
@@ -321,7 +324,7 @@ async function minify(files, options, _fs_module) {
321
324
  configurable: true,
322
325
  enumerable: true,
323
326
  get() {
324
- const map = options.format.source_map.getEncoded();
327
+ const map = format_options.source_map.getEncoded();
325
328
  return (result.map = options.sourceMap.asObject ? map : JSON.stringify(map));
326
329
  },
327
330
  set(value) {
@@ -331,7 +334,7 @@ async function minify(files, options, _fs_module) {
331
334
  });
332
335
  }
333
336
  });
334
- result.decoded_map = options.format.source_map.getDecoded();
337
+ result.decoded_map = format_options.source_map.getDecoded();
335
338
  if (options.sourceMap.url == "inline") {
336
339
  var sourceMap = typeof result.map === "object" ? JSON.stringify(result.map) : result.map;
337
340
  result.code += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + to_base64(sourceMap);
@@ -346,8 +349,8 @@ async function minify(files, options, _fs_module) {
346
349
  options.nameCache.props = cache_to_json(options.mangle.properties.cache);
347
350
  }
348
351
  }
349
- if (options.format && options.format.source_map) {
350
- options.format.source_map.destroy();
352
+ if (format_options && format_options.source_map) {
353
+ format_options.source_map.destroy();
351
354
  }
352
355
  if (timings) {
353
356
  timings.end = Date.now();
package/lib/parse.js CHANGED
@@ -2307,7 +2307,7 @@ function parse($TEXT, options) {
2307
2307
  if (is("operator", "new")) {
2308
2308
  return new_(allow_calls);
2309
2309
  }
2310
- if (is("operator", "import")) {
2310
+ if (is("name", "import") && is_token(peek(), "punc", ".")) {
2311
2311
  return import_meta();
2312
2312
  }
2313
2313
  var start = S.token;
@@ -2803,7 +2803,7 @@ function parse($TEXT, options) {
2803
2803
 
2804
2804
  function import_meta() {
2805
2805
  var start = S.token;
2806
- expect_token("operator", "import");
2806
+ expect_token("name", "import");
2807
2807
  expect_token("punc", ".");
2808
2808
  expect_token("name", "meta");
2809
2809
  return subscripts(new AST_ImportMeta({
@@ -99,36 +99,20 @@ function return_null() { return null; }
99
99
 
100
100
  var MAP = (function() {
101
101
  function MAP(a, tw, allow_splicing = true) {
102
- // Loop but try not to build a new array
102
+ const new_a = [];
103
+
103
104
  for (let i = 0; i < a.length; ++i) {
104
105
  let item = a[i];
105
106
  let ret = item.transform(tw, allow_splicing);
106
107
 
107
- if (ret !== item) {
108
- const a1 = a.slice(0, i);
109
-
110
- // Looks like something was transformed. Change the loop.
111
- if (ret instanceof AST_Node) {
112
- a1.push(ret);
113
- } else if (ret instanceof Splice) {
114
- a1.push(...ret.v);
115
- }
116
-
117
- while ((item = a[++i])) {
118
- const ret = item.transform(tw, true);
119
-
120
- if (ret instanceof AST_Node) {
121
- a1.push(ret);
122
- } else if (ret instanceof Splice) {
123
- a1.push(...ret.v);
124
- }
125
- }
126
-
127
- return a1;
108
+ if (ret instanceof AST_Node) {
109
+ new_a.push(ret);
110
+ } else if (ret instanceof Splice) {
111
+ new_a.push(...ret.v);
128
112
  }
129
113
  }
130
114
 
131
- return a;
115
+ return new_a;
132
116
  }
133
117
 
134
118
  MAP.splice = function(val) { return new Splice(val); };
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.16.4",
7
+ "version": "5.16.6",
8
8
  "engines": {
9
9
  "node": ">=10"
10
10
  },