terser 5.22.0 → 5.24.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,12 @@
1
1
  # Changelog
2
2
 
3
+ ## v5.24.0
4
+ - Improve formatting performance in V8 by keeping a small work string and a large output string
5
+
6
+ ## v5.23.0
7
+ - When top_retain will keep a variable assignment around, inline the assignee when it's shorter than the name (#1434)
8
+ - Remove empty class `static {}` blocks.
9
+
3
10
  ## v5.22.0
4
11
  - Do not `unsafe`ly shorten expressions like a?.toString() when they're conditional.
5
12
  - Avoid running drop_unused in nodes that aren't scopes. Fixes a rare crash.
@@ -2,7 +2,7 @@
2
2
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@jridgewell/source-map')) :
3
3
  typeof define === 'function' && define.amd ? define(['exports', '@jridgewell/source-map'], factory) :
4
4
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Terser = {}, global.sourceMap));
5
- }(this, (function (exports, sourceMap) { 'use strict';
5
+ })(this, (function (exports, sourceMap) { 'use strict';
6
6
 
7
7
  /***********************************************************************
8
8
 
@@ -8928,7 +8928,6 @@ function left_is_object(node) {
8928
8928
 
8929
8929
  ***********************************************************************/
8930
8930
 
8931
- const EXPECT_DIRECTIVE = /^$|[;{][\s\n]*$/;
8932
8931
  const CODE_LINE_BREAK = 10;
8933
8932
  const CODE_SPACE = 32;
8934
8933
 
@@ -8942,6 +8941,7 @@ function is_some_comments(comment) {
8942
8941
  );
8943
8942
  }
8944
8943
 
8944
+ const ROPE_COMMIT_WHEN = 8 * 1000;
8945
8945
  class Rope {
8946
8946
  constructor() {
8947
8947
  this.committed = "";
@@ -8949,7 +8949,13 @@ class Rope {
8949
8949
  }
8950
8950
 
8951
8951
  append(str) {
8952
- this.current += str;
8952
+ /** When `this.current` is too long, commit it. */
8953
+ if (this.current.length > ROPE_COMMIT_WHEN) {
8954
+ this.committed += this.current + str;
8955
+ this.current = "";
8956
+ } else {
8957
+ this.current += str;
8958
+ }
8953
8959
  }
8954
8960
 
8955
8961
  insertAt(char, index) {
@@ -8971,14 +8977,45 @@ class Rope {
8971
8977
  return this.current[index - committed.length];
8972
8978
  }
8973
8979
 
8974
- curLength() {
8975
- return this.current.length;
8980
+ charCodeAt(index) {
8981
+ const { committed } = this;
8982
+ if (index < committed.length) return committed.charCodeAt(index);
8983
+ return this.current.charCodeAt(index - committed.length);
8976
8984
  }
8977
8985
 
8978
8986
  length() {
8979
8987
  return this.committed.length + this.current.length;
8980
8988
  }
8981
8989
 
8990
+ expectDirective() {
8991
+ // /^$|[;{][\s\n]*$/
8992
+
8993
+ let ch, n = this.length();
8994
+
8995
+ if (n <= 0) return true;
8996
+
8997
+ // Skip N whitespace from the end
8998
+ while (
8999
+ (ch = this.charCodeAt(--n))
9000
+ && (ch == CODE_SPACE || ch == CODE_LINE_BREAK)
9001
+ );
9002
+
9003
+ // either ";", or "{", or the string ended
9004
+ return !ch || ch === 59 || ch === 123;
9005
+ }
9006
+
9007
+ hasNLB() {
9008
+ let n = this.length() - 1;
9009
+ while (n >= 0) {
9010
+ const code = this.charCodeAt(n--);
9011
+
9012
+ if (code === CODE_LINE_BREAK) return true;
9013
+ if (code !== CODE_SPACE) return false;
9014
+ }
9015
+ return true;
9016
+ }
9017
+
9018
+
8982
9019
  toString() {
8983
9020
  return this.committed + this.current;
8984
9021
  }
@@ -9184,9 +9221,9 @@ function OutputStream(options) {
9184
9221
  if (current_col > options.max_line_len) {
9185
9222
  if (might_add_newline) {
9186
9223
  OUTPUT.insertAt("\n", might_add_newline);
9187
- const curLength = OUTPUT.curLength();
9224
+ const len_after_newline = OUTPUT.length() - might_add_newline - 1;
9188
9225
  if (mappings) {
9189
- var delta = curLength - current_col;
9226
+ var delta = len_after_newline - current_col;
9190
9227
  mappings.forEach(function(mapping) {
9191
9228
  mapping.line++;
9192
9229
  mapping.col += delta;
@@ -9194,7 +9231,7 @@ function OutputStream(options) {
9194
9231
  }
9195
9232
  current_line++;
9196
9233
  current_pos++;
9197
- current_col = curLength;
9234
+ current_col = len_after_newline;
9198
9235
  }
9199
9236
  }
9200
9237
  if (might_add_newline) {
@@ -9393,23 +9430,6 @@ function OutputStream(options) {
9393
9430
  return OUTPUT.toString();
9394
9431
  }
9395
9432
 
9396
- function has_nlb() {
9397
- const output = OUTPUT.toString();
9398
- let n = output.length - 1;
9399
- while (n >= 0) {
9400
- const code = output.charCodeAt(n);
9401
- if (code === CODE_LINE_BREAK) {
9402
- return true;
9403
- }
9404
-
9405
- if (code !== CODE_SPACE) {
9406
- return false;
9407
- }
9408
- n--;
9409
- }
9410
- return true;
9411
- }
9412
-
9413
9433
  function filter_comment(comment) {
9414
9434
  if (!options.preserve_annotations) {
9415
9435
  comment = comment.replace(r_annotation, " ");
@@ -9490,7 +9510,7 @@ function OutputStream(options) {
9490
9510
 
9491
9511
  comments = comments.filter(comment_filter, node).filter(c => !printed_comments.has(c));
9492
9512
  if (comments.length == 0) return;
9493
- var last_nlb = has_nlb();
9513
+ var last_nlb = OUTPUT.hasNLB();
9494
9514
  comments.forEach(function(c, i) {
9495
9515
  printed_comments.add(c);
9496
9516
  if (!last_nlb) {
@@ -9548,7 +9568,7 @@ function OutputStream(options) {
9548
9568
  print("\n");
9549
9569
  indent();
9550
9570
  need_newline_indented = false;
9551
- } else if (c.nlb && (i > 0 || !has_nlb())) {
9571
+ } else if (c.nlb && (i > 0 || !OUTPUT.hasNLB())) {
9552
9572
  print("\n");
9553
9573
  indent();
9554
9574
  } else if (i > 0 || !tail) {
@@ -9610,7 +9630,7 @@ function OutputStream(options) {
9610
9630
  var encoded = encode_string(str, quote);
9611
9631
  if (escape_directive === true && !encoded.includes("\\")) {
9612
9632
  // Insert semicolons to break directive prologue
9613
- if (!EXPECT_DIRECTIVE.test(OUTPUT.toString())) {
9633
+ if (!OUTPUT.expectDirective()) {
9614
9634
  force_semicolon();
9615
9635
  }
9616
9636
  force_semicolon();
@@ -17696,18 +17716,43 @@ function scope_encloses_variables_in_this_scope(scope, pulled_scope) {
17696
17716
  return false;
17697
17717
  }
17698
17718
 
17719
+ /**
17720
+ * An extra check function for `top_retain` option, compare the length of const identifier
17721
+ * and init value length and return true if init value is longer than identifier. for example:
17722
+ * ```
17723
+ * // top_retain: ["example"]
17724
+ * const example = 100
17725
+ * ```
17726
+ * it will return false because length of "100" is short than identifier "example".
17727
+ */
17728
+ function is_const_symbol_short_than_init_value(def, fixed_value) {
17729
+ if (def.orig.length === 1 && fixed_value) {
17730
+ const init_value_length = fixed_value.size();
17731
+ const identifer_length = def.name.length;
17732
+ return init_value_length > identifer_length;
17733
+ }
17734
+ return true;
17735
+ }
17736
+
17699
17737
  function inline_into_symbolref(self, compressor) {
17700
17738
  const parent = compressor.parent();
17701
-
17702
17739
  const def = self.definition();
17703
17740
  const nearest_scope = compressor.find_scope();
17704
- if (compressor.top_retain && def.global && compressor.top_retain(def)) {
17741
+ let fixed = self.fixed_value();
17742
+ if (
17743
+ compressor.top_retain &&
17744
+ def.global &&
17745
+ compressor.top_retain(def) &&
17746
+ // when identifier is in top_retain option dose not mean we can always inline it.
17747
+ // if identifier name is longer then init value, we can replace it.
17748
+ is_const_symbol_short_than_init_value(def, fixed)
17749
+ ) {
17750
+ // keep it
17705
17751
  def.fixed = false;
17706
17752
  def.single_use = false;
17707
17753
  return self;
17708
17754
  }
17709
17755
 
17710
- let fixed = self.fixed_value();
17711
17756
  let single_use = def.single_use
17712
17757
  && !(parent instanceof AST_Call
17713
17758
  && (parent.is_callee_pure(compressor))
@@ -21643,8 +21688,14 @@ def_optimize(AST_Function, function(self, compressor) {
21643
21688
  });
21644
21689
 
21645
21690
  def_optimize(AST_Class, function(self) {
21646
- // HACK to avoid compress failure.
21647
- // AST_Class is not really an AST_Scope/AST_Block as it lacks a body.
21691
+ for (let i = 0; i < self.properties.length; i++) {
21692
+ const prop = self.properties[i];
21693
+ if (prop instanceof AST_ClassStaticBlock && prop.body.length == 0) {
21694
+ self.properties.splice(i, 1);
21695
+ i--;
21696
+ }
21697
+ }
21698
+
21648
21699
  return self;
21649
21700
  });
21650
21701
 
@@ -31264,4 +31315,4 @@ exports._default_options = _default_options;
31264
31315
  exports._run_cli = run_cli;
31265
31316
  exports.minify = minify;
31266
31317
 
31267
- })));
31318
+ }));
@@ -3549,8 +3549,14 @@ def_optimize(AST_Function, function(self, compressor) {
3549
3549
  });
3550
3550
 
3551
3551
  def_optimize(AST_Class, function(self) {
3552
- // HACK to avoid compress failure.
3553
- // AST_Class is not really an AST_Scope/AST_Block as it lacks a body.
3552
+ for (let i = 0; i < self.properties.length; i++) {
3553
+ const prop = self.properties[i];
3554
+ if (prop instanceof AST_ClassStaticBlock && prop.body.length == 0) {
3555
+ self.properties.splice(i, 1);
3556
+ i--;
3557
+ }
3558
+ }
3559
+
3554
3560
  return self;
3555
3561
  });
3556
3562
 
@@ -84,7 +84,7 @@ import {
84
84
 
85
85
  _INLINE,
86
86
  _NOINLINE,
87
- _PURE
87
+ _PURE,
88
88
  } from "../ast.js";
89
89
  import { make_node, has_annotation } from "../utils/index.js";
90
90
  import "../size.js";
@@ -148,18 +148,43 @@ function scope_encloses_variables_in_this_scope(scope, pulled_scope) {
148
148
  return false;
149
149
  }
150
150
 
151
+ /**
152
+ * An extra check function for `top_retain` option, compare the length of const identifier
153
+ * and init value length and return true if init value is longer than identifier. for example:
154
+ * ```
155
+ * // top_retain: ["example"]
156
+ * const example = 100
157
+ * ```
158
+ * it will return false because length of "100" is short than identifier "example".
159
+ */
160
+ function is_const_symbol_short_than_init_value(def, fixed_value) {
161
+ if (def.orig.length === 1 && fixed_value) {
162
+ const init_value_length = fixed_value.size();
163
+ const identifer_length = def.name.length;
164
+ return init_value_length > identifer_length;
165
+ }
166
+ return true;
167
+ }
168
+
151
169
  export function inline_into_symbolref(self, compressor) {
152
170
  const parent = compressor.parent();
153
-
154
171
  const def = self.definition();
155
172
  const nearest_scope = compressor.find_scope();
156
- if (compressor.top_retain && def.global && compressor.top_retain(def)) {
173
+ let fixed = self.fixed_value();
174
+ if (
175
+ compressor.top_retain &&
176
+ def.global &&
177
+ compressor.top_retain(def) &&
178
+ // when identifier is in top_retain option dose not mean we can always inline it.
179
+ // if identifier name is longer then init value, we can replace it.
180
+ is_const_symbol_short_than_init_value(def, fixed)
181
+ ) {
182
+ // keep it
157
183
  def.fixed = false;
158
184
  def.single_use = false;
159
185
  return self;
160
186
  }
161
187
 
162
- let fixed = self.fixed_value();
163
188
  let single_use = def.single_use
164
189
  && !(parent instanceof AST_Call
165
190
  && (parent.is_callee_pure(compressor))
package/lib/output.js CHANGED
@@ -166,7 +166,6 @@ import {
166
166
  ALL_RESERVED_WORDS,
167
167
  } from "./parse.js";
168
168
 
169
- const EXPECT_DIRECTIVE = /^$|[;{][\s\n]*$/;
170
169
  const CODE_LINE_BREAK = 10;
171
170
  const CODE_SPACE = 32;
172
171
 
@@ -180,6 +179,7 @@ function is_some_comments(comment) {
180
179
  );
181
180
  }
182
181
 
182
+ const ROPE_COMMIT_WHEN = 8 * 1000;
183
183
  class Rope {
184
184
  constructor() {
185
185
  this.committed = "";
@@ -187,7 +187,13 @@ class Rope {
187
187
  }
188
188
 
189
189
  append(str) {
190
- this.current += str;
190
+ /** When `this.current` is too long, commit it. */
191
+ if (this.current.length > ROPE_COMMIT_WHEN) {
192
+ this.committed += this.current + str;
193
+ this.current = "";
194
+ } else {
195
+ this.current += str;
196
+ }
191
197
  }
192
198
 
193
199
  insertAt(char, index) {
@@ -209,14 +215,45 @@ class Rope {
209
215
  return this.current[index - committed.length];
210
216
  }
211
217
 
212
- curLength() {
213
- return this.current.length;
218
+ charCodeAt(index) {
219
+ const { committed } = this;
220
+ if (index < committed.length) return committed.charCodeAt(index);
221
+ return this.current.charCodeAt(index - committed.length);
214
222
  }
215
223
 
216
224
  length() {
217
225
  return this.committed.length + this.current.length;
218
226
  }
219
227
 
228
+ expectDirective() {
229
+ // /^$|[;{][\s\n]*$/
230
+
231
+ let ch, n = this.length();
232
+
233
+ if (n <= 0) return true;
234
+
235
+ // Skip N whitespace from the end
236
+ while (
237
+ (ch = this.charCodeAt(--n))
238
+ && (ch == CODE_SPACE || ch == CODE_LINE_BREAK)
239
+ );
240
+
241
+ // either ";", or "{", or the string ended
242
+ return !ch || ch === 59 || ch === 123;
243
+ }
244
+
245
+ hasNLB() {
246
+ let n = this.length() - 1;
247
+ while (n >= 0) {
248
+ const code = this.charCodeAt(n--);
249
+
250
+ if (code === CODE_LINE_BREAK) return true;
251
+ if (code !== CODE_SPACE) return false;
252
+ }
253
+ return true;
254
+ }
255
+
256
+
220
257
  toString() {
221
258
  return this.committed + this.current;
222
259
  }
@@ -422,9 +459,9 @@ function OutputStream(options) {
422
459
  if (current_col > options.max_line_len) {
423
460
  if (might_add_newline) {
424
461
  OUTPUT.insertAt("\n", might_add_newline);
425
- const curLength = OUTPUT.curLength();
462
+ const len_after_newline = OUTPUT.length() - might_add_newline - 1;
426
463
  if (mappings) {
427
- var delta = curLength - current_col;
464
+ var delta = len_after_newline - current_col;
428
465
  mappings.forEach(function(mapping) {
429
466
  mapping.line++;
430
467
  mapping.col += delta;
@@ -432,7 +469,7 @@ function OutputStream(options) {
432
469
  }
433
470
  current_line++;
434
471
  current_pos++;
435
- current_col = curLength;
472
+ current_col = len_after_newline;
436
473
  }
437
474
  }
438
475
  if (might_add_newline) {
@@ -631,23 +668,6 @@ function OutputStream(options) {
631
668
  return OUTPUT.toString();
632
669
  }
633
670
 
634
- function has_nlb() {
635
- const output = OUTPUT.toString();
636
- let n = output.length - 1;
637
- while (n >= 0) {
638
- const code = output.charCodeAt(n);
639
- if (code === CODE_LINE_BREAK) {
640
- return true;
641
- }
642
-
643
- if (code !== CODE_SPACE) {
644
- return false;
645
- }
646
- n--;
647
- }
648
- return true;
649
- }
650
-
651
671
  function filter_comment(comment) {
652
672
  if (!options.preserve_annotations) {
653
673
  comment = comment.replace(r_annotation, " ");
@@ -728,7 +748,7 @@ function OutputStream(options) {
728
748
 
729
749
  comments = comments.filter(comment_filter, node).filter(c => !printed_comments.has(c));
730
750
  if (comments.length == 0) return;
731
- var last_nlb = has_nlb();
751
+ var last_nlb = OUTPUT.hasNLB();
732
752
  comments.forEach(function(c, i) {
733
753
  printed_comments.add(c);
734
754
  if (!last_nlb) {
@@ -786,7 +806,7 @@ function OutputStream(options) {
786
806
  print("\n");
787
807
  indent();
788
808
  need_newline_indented = false;
789
- } else if (c.nlb && (i > 0 || !has_nlb())) {
809
+ } else if (c.nlb && (i > 0 || !OUTPUT.hasNLB())) {
790
810
  print("\n");
791
811
  indent();
792
812
  } else if (i > 0 || !tail) {
@@ -848,7 +868,7 @@ function OutputStream(options) {
848
868
  var encoded = encode_string(str, quote);
849
869
  if (escape_directive === true && !encoded.includes("\\")) {
850
870
  // Insert semicolons to break directive prologue
851
- if (!EXPECT_DIRECTIVE.test(OUTPUT.toString())) {
871
+ if (!OUTPUT.expectDirective()) {
852
872
  force_semicolon();
853
873
  }
854
874
  force_semicolon();
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.22.0",
7
+ "version": "5.24.0",
8
8
  "engines": {
9
9
  "node": ">=10"
10
10
  },