terser 5.23.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,8 @@
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
+
3
6
  ## v5.23.0
4
7
  - When top_retain will keep a variable assignment around, inline the assignee when it's shorter than the name (#1434)
5
8
  - Remove empty class `static {}` blocks.
@@ -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();
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.23.0",
7
+ "version": "5.24.0",
8
8
  "engines": {
9
9
  "node": ">=10"
10
10
  },