rollup 3.4.0 → 3.5.0-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.
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  @license
3
- Rollup.js v3.4.0
4
- Tue, 22 Nov 2022 05:15:54 GMT - commit 780e3421e8a498f3248fd7d8506e97fcee8dd1e6
3
+ Rollup.js v3.5.0-0
4
+ Fri, 25 Nov 2022 05:53:50 GMT - commit b8beb21aa83e193ed6ef82f06127e95a7ef5fe22
5
5
 
6
6
  https://github.com/rollup/rollup
7
7
 
@@ -16,7 +16,7 @@ import { promises } from 'node:fs';
16
16
  import { EventEmitter } from 'node:events';
17
17
  import * as tty from 'tty';
18
18
 
19
- var version$1 = "3.4.0";
19
+ var version$1 = "3.5.0-0";
20
20
 
21
21
  var charToInteger = {};
22
22
  var chars$1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
@@ -1776,7 +1776,7 @@ class ExpressionEntity {
1776
1776
  return UnknownValue;
1777
1777
  }
1778
1778
  getReturnExpressionWhenCalledAtPath(_path, _interaction, _recursionTracker, _origin) {
1779
- return UNKNOWN_EXPRESSION;
1779
+ return UNKNOWN_RETURN_EXPRESSION;
1780
1780
  }
1781
1781
  hasEffectsOnInteractionAtPath(_path, _interaction, _context) {
1782
1782
  return true;
@@ -1795,6 +1795,10 @@ class ExpressionEntity {
1795
1795
  }
1796
1796
  const UNKNOWN_EXPRESSION = new (class UnknownExpression extends ExpressionEntity {
1797
1797
  })();
1798
+ const UNKNOWN_RETURN_EXPRESSION = [
1799
+ UNKNOWN_EXPRESSION,
1800
+ false
1801
+ ];
1798
1802
 
1799
1803
  const INTERACTION_ACCESSED = 0;
1800
1804
  const INTERACTION_ASSIGNED = 1;
@@ -4930,7 +4934,7 @@ const UNKNOWN_LITERAL_BOOLEAN = new (class UnknownBoolean extends ExpressionEnti
4930
4934
  if (path.length === 1) {
4931
4935
  return getMemberReturnExpressionWhenCalled(literalBooleanMembers, path[0]);
4932
4936
  }
4933
- return UNKNOWN_EXPRESSION;
4937
+ return UNKNOWN_RETURN_EXPRESSION;
4934
4938
  }
4935
4939
  hasEffectsOnInteractionAtPath(path, interaction, context) {
4936
4940
  if (interaction.type === INTERACTION_ACCESSED) {
@@ -4953,7 +4957,7 @@ const UNKNOWN_LITERAL_NUMBER = new (class UnknownNumber extends ExpressionEntity
4953
4957
  if (path.length === 1) {
4954
4958
  return getMemberReturnExpressionWhenCalled(literalNumberMembers, path[0]);
4955
4959
  }
4956
- return UNKNOWN_EXPRESSION;
4960
+ return UNKNOWN_RETURN_EXPRESSION;
4957
4961
  }
4958
4962
  hasEffectsOnInteractionAtPath(path, interaction, context) {
4959
4963
  if (interaction.type === INTERACTION_ACCESSED) {
@@ -4976,7 +4980,7 @@ const UNKNOWN_LITERAL_STRING = new (class UnknownString extends ExpressionEntity
4976
4980
  if (path.length === 1) {
4977
4981
  return getMemberReturnExpressionWhenCalled(literalStringMembers, path[0]);
4978
4982
  }
4979
- return UNKNOWN_EXPRESSION;
4983
+ return UNKNOWN_RETURN_EXPRESSION;
4980
4984
  }
4981
4985
  hasEffectsOnInteractionAtPath(path, interaction, context) {
4982
4986
  if (interaction.type === INTERACTION_ACCESSED) {
@@ -5097,8 +5101,8 @@ function hasMemberEffectWhenCalled(members, memberName, interaction, context) {
5097
5101
  }
5098
5102
  function getMemberReturnExpressionWhenCalled(members, memberName) {
5099
5103
  if (typeof memberName !== 'string' || !members[memberName])
5100
- return UNKNOWN_EXPRESSION;
5101
- return members[memberName].returns;
5104
+ return UNKNOWN_RETURN_EXPRESSION;
5105
+ return [members[memberName].returns, false];
5102
5106
  }
5103
5107
 
5104
5108
  // AST walker module for Mozilla Parser API compatible trees
@@ -5748,12 +5752,15 @@ class Method extends ExpressionEntity {
5748
5752
  }
5749
5753
  getReturnExpressionWhenCalledAtPath(path, { thisArg }) {
5750
5754
  if (path.length > 0) {
5751
- return UNKNOWN_EXPRESSION;
5755
+ return UNKNOWN_RETURN_EXPRESSION;
5752
5756
  }
5753
- return (this.description.returnsPrimitive ||
5754
- (this.description.returns === 'self'
5755
- ? thisArg || UNKNOWN_EXPRESSION
5756
- : this.description.returns()));
5757
+ return [
5758
+ this.description.returnsPrimitive ||
5759
+ (this.description.returns === 'self'
5760
+ ? thisArg || UNKNOWN_EXPRESSION
5761
+ : this.description.returns()),
5762
+ false
5763
+ ];
5757
5764
  }
5758
5765
  hasEffectsOnInteractionAtPath(path, interaction, context) {
5759
5766
  const { type } = interaction;
@@ -5996,7 +6003,7 @@ class ObjectEntity extends ExpressionEntity {
5996
6003
  }
5997
6004
  getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin) {
5998
6005
  if (path.length === 0) {
5999
- return UNKNOWN_EXPRESSION;
6006
+ return UNKNOWN_RETURN_EXPRESSION;
6000
6007
  }
6001
6008
  const [key, ...subPath] = path;
6002
6009
  const expressionAtPath = this.getMemberExpressionAndTrackDeopt(key, origin);
@@ -6006,7 +6013,7 @@ class ObjectEntity extends ExpressionEntity {
6006
6013
  if (this.prototypeExpression) {
6007
6014
  return this.prototypeExpression.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin);
6008
6015
  }
6009
- return UNKNOWN_EXPRESSION;
6016
+ return UNKNOWN_RETURN_EXPRESSION;
6010
6017
  }
6011
6018
  hasEffectsOnInteractionAtPath(path, interaction, context) {
6012
6019
  const [key, ...subPath] = path;
@@ -6478,12 +6485,12 @@ class LocalVariable extends Variable {
6478
6485
  }
6479
6486
  getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin) {
6480
6487
  if (this.isReassigned || !this.init) {
6481
- return UNKNOWN_EXPRESSION;
6488
+ return UNKNOWN_RETURN_EXPRESSION;
6482
6489
  }
6483
6490
  return recursionTracker.withTrackedEntityAtPath(path, this.init, () => {
6484
6491
  this.expressionsToBeDeoptimized.push(origin);
6485
6492
  return this.init.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin);
6486
- }, UNKNOWN_EXPRESSION);
6493
+ }, UNKNOWN_RETURN_EXPRESSION);
6487
6494
  }
6488
6495
  hasEffectsOnInteractionAtPath(path, interaction, context) {
6489
6496
  switch (interaction.type) {
@@ -6840,6 +6847,19 @@ function is_reference (node, parent) {
6840
6847
  return false;
6841
6848
  }
6842
6849
 
6850
+ const PureFunctionKey = Symbol('PureFunction');
6851
+ const getPureFunctions = ({ treeshake }) => {
6852
+ const pureFunctions = Object.create(null);
6853
+ for (const functionName of treeshake ? treeshake.manualPureFunctions : []) {
6854
+ let currentFunctions = pureFunctions;
6855
+ for (const pathSegment of functionName.split('.')) {
6856
+ currentFunctions = currentFunctions[pathSegment] || (currentFunctions[pathSegment] = Object.create(null));
6857
+ }
6858
+ currentFunctions[PureFunctionKey] = true;
6859
+ }
6860
+ return pureFunctions;
6861
+ };
6862
+
6843
6863
  /* eslint sort-keys: "off" */
6844
6864
  const ValueProperties = Symbol('Value Properties');
6845
6865
  const getTruthyLiteralValue = () => UnknownTruthyValue;
@@ -7818,7 +7838,8 @@ class Identifier extends NodeBase {
7818
7838
  return this.getVariableRespectingTDZ().getLiteralValueAtPath(path, recursionTracker, origin);
7819
7839
  }
7820
7840
  getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin) {
7821
- return this.getVariableRespectingTDZ().getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin);
7841
+ const [expression, isPure] = this.getVariableRespectingTDZ().getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin);
7842
+ return [expression, isPure || this.isPureFunction(path)];
7822
7843
  }
7823
7844
  hasEffects(context) {
7824
7845
  if (!this.deoptimized)
@@ -7828,19 +7849,22 @@ class Identifier extends NodeBase {
7828
7849
  }
7829
7850
  return (this.context.options.treeshake.unknownGlobalSideEffects &&
7830
7851
  this.variable instanceof GlobalVariable &&
7852
+ !this.isPureFunction(EMPTY_PATH) &&
7831
7853
  this.variable.hasEffectsOnInteractionAtPath(EMPTY_PATH, NODE_INTERACTION_UNKNOWN_ACCESS, context));
7832
7854
  }
7833
7855
  hasEffectsOnInteractionAtPath(path, interaction, context) {
7834
7856
  switch (interaction.type) {
7835
7857
  case INTERACTION_ACCESSED: {
7836
7858
  return (this.variable !== null &&
7859
+ !this.isPureFunction(path) &&
7837
7860
  this.getVariableRespectingTDZ().hasEffectsOnInteractionAtPath(path, interaction, context));
7838
7861
  }
7839
7862
  case INTERACTION_ASSIGNED: {
7840
7863
  return (path.length > 0 ? this.getVariableRespectingTDZ() : this.variable).hasEffectsOnInteractionAtPath(path, interaction, context);
7841
7864
  }
7842
7865
  case INTERACTION_CALLED: {
7843
- return this.getVariableRespectingTDZ().hasEffectsOnInteractionAtPath(path, interaction, context);
7866
+ return (!this.isPureFunction(path) &&
7867
+ this.getVariableRespectingTDZ().hasEffectsOnInteractionAtPath(path, interaction, context));
7844
7868
  }
7845
7869
  }
7846
7870
  }
@@ -7922,6 +7946,21 @@ class Identifier extends NodeBase {
7922
7946
  }
7923
7947
  return this.variable;
7924
7948
  }
7949
+ isPureFunction(path) {
7950
+ let currentPureFunction = this.context.manualPureFunctions[this.name];
7951
+ for (const segment of path) {
7952
+ if (currentPureFunction) {
7953
+ if (currentPureFunction[PureFunctionKey]) {
7954
+ return true;
7955
+ }
7956
+ currentPureFunction = currentPureFunction[segment];
7957
+ }
7958
+ else {
7959
+ return false;
7960
+ }
7961
+ }
7962
+ return currentPureFunction?.[PureFunctionKey];
7963
+ }
7925
7964
  }
7926
7965
  function closestParentFunctionOrProgram(node) {
7927
7966
  while (node && !/^Program|Function/.test(node.type)) {
@@ -8243,9 +8282,9 @@ class FunctionBase extends NodeBase {
8243
8282
  this.scope.getReturnExpression().deoptimizePath(UNKNOWN_PATH);
8244
8283
  this.context.requestTreeshakingPass();
8245
8284
  }
8246
- return UNKNOWN_EXPRESSION;
8285
+ return UNKNOWN_RETURN_EXPRESSION;
8247
8286
  }
8248
- return this.scope.getReturnExpression();
8287
+ return [this.scope.getReturnExpression(), false];
8249
8288
  }
8250
8289
  hasEffectsOnInteractionAtPath(path, interaction, context) {
8251
8290
  if (path.length > 0 || interaction.type !== INTERACTION_CALLED) {
@@ -8844,7 +8883,7 @@ class Literal extends NodeBase {
8844
8883
  }
8845
8884
  getReturnExpressionWhenCalledAtPath(path) {
8846
8885
  if (path.length !== 1)
8847
- return UNKNOWN_EXPRESSION;
8886
+ return UNKNOWN_RETURN_EXPRESSION;
8848
8887
  return getMemberReturnExpressionWhenCalled(this.members, path[0]);
8849
8888
  }
8850
8889
  hasEffectsOnInteractionAtPath(path, interaction, context) {
@@ -8997,13 +9036,13 @@ class MemberExpression extends NodeBase {
8997
9036
  return this.variable.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin);
8998
9037
  }
8999
9038
  if (this.isUndefined) {
9000
- return UNDEFINED_EXPRESSION;
9039
+ return [UNDEFINED_EXPRESSION, false];
9001
9040
  }
9002
9041
  this.expressionsToBeDeoptimized.push(origin);
9003
9042
  if (path.length < MAX_PATH_DEPTH) {
9004
9043
  return this.object.getReturnExpressionWhenCalledAtPath([this.getPropertyKey(), ...path], interaction, recursionTracker, origin);
9005
9044
  }
9006
- return UNKNOWN_EXPRESSION;
9045
+ return UNKNOWN_RETURN_EXPRESSION;
9007
9046
  }
9008
9047
  hasEffects(context) {
9009
9048
  if (!this.deoptimized)
@@ -9180,8 +9219,8 @@ class CallExpressionBase extends NodeBase {
9180
9219
  this.expressionsToBeDeoptimized = new Set();
9181
9220
  }
9182
9221
  deoptimizeCache() {
9183
- if (this.returnExpression !== UNKNOWN_EXPRESSION) {
9184
- this.returnExpression = UNKNOWN_EXPRESSION;
9222
+ if (this.returnExpression?.[0] !== UNKNOWN_EXPRESSION) {
9223
+ this.returnExpression = UNKNOWN_RETURN_EXPRESSION;
9185
9224
  for (const expression of this.deoptimizableDependentExpressions) {
9186
9225
  expression.deoptimizeCache();
9187
9226
  }
@@ -9195,13 +9234,15 @@ class CallExpressionBase extends NodeBase {
9195
9234
  this.context.deoptimizationTracker.trackEntityAtPathAndGetIfTracked(path, this)) {
9196
9235
  return;
9197
9236
  }
9198
- const returnExpression = this.getReturnExpression();
9237
+ const [returnExpression] = this.getReturnExpression();
9199
9238
  if (returnExpression !== UNKNOWN_EXPRESSION) {
9200
9239
  returnExpression.deoptimizePath(path);
9201
9240
  }
9202
9241
  }
9203
9242
  deoptimizeThisOnInteractionAtPath(interaction, path, recursionTracker) {
9204
- const returnExpression = this.getReturnExpression(recursionTracker);
9243
+ const [returnExpression, isPure] = this.getReturnExpression(recursionTracker);
9244
+ if (isPure)
9245
+ return;
9205
9246
  if (returnExpression === UNKNOWN_EXPRESSION) {
9206
9247
  interaction.thisArg.deoptimizePath(UNKNOWN_PATH);
9207
9248
  }
@@ -9213,7 +9254,7 @@ class CallExpressionBase extends NodeBase {
9213
9254
  }
9214
9255
  }
9215
9256
  getLiteralValueAtPath(path, recursionTracker, origin) {
9216
- const returnExpression = this.getReturnExpression(recursionTracker);
9257
+ const [returnExpression] = this.getReturnExpression(recursionTracker);
9217
9258
  if (returnExpression === UNKNOWN_EXPRESSION) {
9218
9259
  return UnknownValue;
9219
9260
  }
@@ -9224,13 +9265,14 @@ class CallExpressionBase extends NodeBase {
9224
9265
  }
9225
9266
  getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin) {
9226
9267
  const returnExpression = this.getReturnExpression(recursionTracker);
9227
- if (this.returnExpression === UNKNOWN_EXPRESSION) {
9228
- return UNKNOWN_EXPRESSION;
9268
+ if (returnExpression[0] === UNKNOWN_EXPRESSION) {
9269
+ return returnExpression;
9229
9270
  }
9230
9271
  return recursionTracker.withTrackedEntityAtPath(path, returnExpression, () => {
9231
9272
  this.deoptimizableDependentExpressions.push(origin);
9232
- return returnExpression.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin);
9233
- }, UNKNOWN_EXPRESSION);
9273
+ const [expression, isPure] = returnExpression[0].getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin);
9274
+ return [expression, isPure || returnExpression[1]];
9275
+ }, UNKNOWN_RETURN_EXPRESSION);
9234
9276
  }
9235
9277
  hasEffectsOnInteractionAtPath(path, interaction, context) {
9236
9278
  const { type } = interaction;
@@ -9245,7 +9287,9 @@ class CallExpressionBase extends NodeBase {
9245
9287
  : context.accessed).trackEntityAtPathAndGetIfTracked(path, this)) {
9246
9288
  return false;
9247
9289
  }
9248
- return this.getReturnExpression().hasEffectsOnInteractionAtPath(path, interaction, context);
9290
+ const [returnExpression, isPure] = this.getReturnExpression();
9291
+ return ((type === INTERACTION_ASSIGNED || !isPure) &&
9292
+ returnExpression.hasEffectsOnInteractionAtPath(path, interaction, context));
9249
9293
  }
9250
9294
  }
9251
9295
 
@@ -9324,7 +9368,7 @@ class CallExpression extends CallExpressionBase {
9324
9368
  }
9325
9369
  getReturnExpression(recursionTracker = SHARED_RECURSION_TRACKER) {
9326
9370
  if (this.returnExpression === null) {
9327
- this.returnExpression = UNKNOWN_EXPRESSION;
9371
+ this.returnExpression = UNKNOWN_RETURN_EXPRESSION;
9328
9372
  return (this.returnExpression = this.callee.getReturnExpressionWhenCalledAtPath(EMPTY_PATH, this.interaction, recursionTracker, this));
9329
9373
  }
9330
9374
  return this.returnExpression;
@@ -9408,7 +9452,7 @@ class MethodBase extends NodeBase {
9408
9452
  // expressions, there is no known situation where a getter is deoptimized.
9409
9453
  deoptimizeCache() { }
9410
9454
  deoptimizePath(path) {
9411
- this.getAccessedValue().deoptimizePath(path);
9455
+ this.getAccessedValue()[0].deoptimizePath(path);
9412
9456
  }
9413
9457
  deoptimizeThisOnInteractionAtPath(interaction, path, recursionTracker) {
9414
9458
  if (interaction.type === INTERACTION_ACCESSED && this.kind === 'get' && path.length === 0) {
@@ -9427,13 +9471,13 @@ class MethodBase extends NodeBase {
9427
9471
  withNew: false
9428
9472
  }, EMPTY_PATH, recursionTracker);
9429
9473
  }
9430
- this.getAccessedValue().deoptimizeThisOnInteractionAtPath(interaction, path, recursionTracker);
9474
+ this.getAccessedValue()[0].deoptimizeThisOnInteractionAtPath(interaction, path, recursionTracker);
9431
9475
  }
9432
9476
  getLiteralValueAtPath(path, recursionTracker, origin) {
9433
- return this.getAccessedValue().getLiteralValueAtPath(path, recursionTracker, origin);
9477
+ return this.getAccessedValue()[0].getLiteralValueAtPath(path, recursionTracker, origin);
9434
9478
  }
9435
9479
  getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin) {
9436
- return this.getAccessedValue().getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin);
9480
+ return this.getAccessedValue()[0].getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin);
9437
9481
  }
9438
9482
  hasEffects(context) {
9439
9483
  return this.key.hasEffects(context);
@@ -9456,17 +9500,17 @@ class MethodBase extends NodeBase {
9456
9500
  withNew: false
9457
9501
  }, context);
9458
9502
  }
9459
- return this.getAccessedValue().hasEffectsOnInteractionAtPath(path, interaction, context);
9503
+ return this.getAccessedValue()[0].hasEffectsOnInteractionAtPath(path, interaction, context);
9460
9504
  }
9461
9505
  applyDeoptimizations() { }
9462
9506
  getAccessedValue() {
9463
9507
  if (this.accessedValue === null) {
9464
9508
  if (this.kind === 'get') {
9465
- this.accessedValue = UNKNOWN_EXPRESSION;
9509
+ this.accessedValue = UNKNOWN_RETURN_EXPRESSION;
9466
9510
  return (this.accessedValue = this.value.getReturnExpressionWhenCalledAtPath(EMPTY_PATH, NODE_INTERACTION_UNKNOWN_CALL, SHARED_RECURSION_TRACKER, this));
9467
9511
  }
9468
9512
  else {
9469
- return (this.accessedValue = this.value);
9513
+ return (this.accessedValue = [this.value, false]);
9470
9514
  }
9471
9515
  }
9472
9516
  return this.accessedValue;
@@ -9679,7 +9723,10 @@ class MultiExpression extends ExpressionEntity {
9679
9723
  }
9680
9724
  }
9681
9725
  getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin) {
9682
- return new MultiExpression(this.expressions.map(expression => expression.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin)));
9726
+ return [
9727
+ new MultiExpression(this.expressions.map(expression => expression.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin)[0])),
9728
+ false
9729
+ ];
9683
9730
  }
9684
9731
  hasEffectsOnInteractionAtPath(path, interaction, context) {
9685
9732
  for (const expression of this.expressions) {
@@ -9731,10 +9778,13 @@ class ConditionalExpression extends NodeBase {
9731
9778
  getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin) {
9732
9779
  const usedBranch = this.getUsedBranch();
9733
9780
  if (!usedBranch)
9734
- return new MultiExpression([
9735
- this.consequent.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin),
9736
- this.alternate.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin)
9737
- ]);
9781
+ return [
9782
+ new MultiExpression([
9783
+ this.consequent.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin)[0],
9784
+ this.alternate.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin)[0]
9785
+ ]),
9786
+ false
9787
+ ];
9738
9788
  this.expressionsToBeDeoptimized.push(origin);
9739
9789
  return usedBranch.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin);
9740
9790
  }
@@ -10859,10 +10909,13 @@ class LogicalExpression extends NodeBase {
10859
10909
  getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin) {
10860
10910
  const usedBranch = this.getUsedBranch();
10861
10911
  if (!usedBranch)
10862
- return new MultiExpression([
10863
- this.left.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin),
10864
- this.right.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin)
10865
- ]);
10912
+ return [
10913
+ new MultiExpression([
10914
+ this.left.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin)[0],
10915
+ this.right.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin)[0]
10916
+ ]),
10917
+ false
10918
+ ];
10866
10919
  this.expressionsToBeDeoptimized.push(origin);
10867
10920
  return usedBranch.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin);
10868
10921
  }
@@ -11200,7 +11253,12 @@ class PrivateIdentifier extends NodeBase {
11200
11253
  class Program extends NodeBase {
11201
11254
  constructor() {
11202
11255
  super(...arguments);
11203
- this.hasCachedEffect = false;
11256
+ this.hasCachedEffect = null;
11257
+ }
11258
+ hasCachedEffects() {
11259
+ return this.hasCachedEffect === null
11260
+ ? (this.hasCachedEffect = this.hasEffects(createHasEffectsContext()))
11261
+ : this.hasCachedEffect;
11204
11262
  }
11205
11263
  hasEffects(context) {
11206
11264
  // We are caching here to later more efficiently identify side-effect-free modules
@@ -11288,7 +11346,7 @@ class PropertyDefinition extends NodeBase {
11288
11346
  getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin) {
11289
11347
  return this.value
11290
11348
  ? this.value.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin)
11291
- : UNKNOWN_EXPRESSION;
11349
+ : UNKNOWN_RETURN_EXPRESSION;
11292
11350
  }
11293
11351
  hasEffects(context) {
11294
11352
  return this.key.hasEffects(context) || (this.static && !!this.value?.hasEffects(context));
@@ -11579,7 +11637,7 @@ class TaggedTemplateExpression extends CallExpressionBase {
11579
11637
  this.quasi.include(context, includeChildrenRecursively);
11580
11638
  }
11581
11639
  this.tag.includeCallArguments(context, this.interaction.args);
11582
- const returnExpression = this.getReturnExpression();
11640
+ const [returnExpression] = this.getReturnExpression();
11583
11641
  if (!returnExpression.included) {
11584
11642
  returnExpression.include(context, false);
11585
11643
  }
@@ -11609,7 +11667,7 @@ class TaggedTemplateExpression extends CallExpressionBase {
11609
11667
  }
11610
11668
  getReturnExpression(recursionTracker = SHARED_RECURSION_TRACKER) {
11611
11669
  if (this.returnExpression === null) {
11612
- this.returnExpression = UNKNOWN_EXPRESSION;
11670
+ this.returnExpression = UNKNOWN_RETURN_EXPRESSION;
11613
11671
  return (this.returnExpression = this.tag.getReturnExpressionWhenCalledAtPath(EMPTY_PATH, this.interaction, recursionTracker, this));
11614
11672
  }
11615
11673
  return this.returnExpression;
@@ -11642,7 +11700,7 @@ class TemplateLiteral extends NodeBase {
11642
11700
  }
11643
11701
  getReturnExpressionWhenCalledAtPath(path) {
11644
11702
  if (path.length !== 1) {
11645
- return UNKNOWN_EXPRESSION;
11703
+ return UNKNOWN_RETURN_EXPRESSION;
11646
11704
  }
11647
11705
  return getMemberReturnExpressionWhenCalled(literalStringMembers, path[0]);
11648
11706
  }
@@ -13043,8 +13101,7 @@ class Module {
13043
13101
  return [null];
13044
13102
  }
13045
13103
  hasEffects() {
13046
- return (this.info.moduleSideEffects === 'no-treeshake' ||
13047
- (this.ast.included && this.ast.hasEffects(createHasEffectsContext())));
13104
+ return this.info.moduleSideEffects === 'no-treeshake' || this.ast.hasCachedEffects();
13048
13105
  }
13049
13106
  include() {
13050
13107
  const context = createInclusionContext();
@@ -13156,6 +13213,7 @@ class Module {
13156
13213
  includeDynamicImport: this.includeDynamicImport.bind(this),
13157
13214
  includeVariableInModule: this.includeVariableInModule.bind(this),
13158
13215
  magicString: this.magicString,
13216
+ manualPureFunctions: this.graph.pureFunctions,
13159
13217
  module: this,
13160
13218
  moduleContext: this.context,
13161
13219
  options: this.options,
@@ -15640,12 +15698,132 @@ function getImportedBindingsPerDependency(renderedDependencies, resolveFileName)
15640
15698
  const QUERY_HASH_REGEX = /[#?]/;
15641
15699
  const resolveFileName = (dependency) => dependency.getFileName();
15642
15700
 
15701
+ const BYTE_UNITS = [
15702
+ 'B',
15703
+ 'kB',
15704
+ 'MB',
15705
+ 'GB',
15706
+ 'TB',
15707
+ 'PB',
15708
+ 'EB',
15709
+ 'ZB',
15710
+ 'YB',
15711
+ ];
15712
+
15713
+ const BIBYTE_UNITS = [
15714
+ 'B',
15715
+ 'kiB',
15716
+ 'MiB',
15717
+ 'GiB',
15718
+ 'TiB',
15719
+ 'PiB',
15720
+ 'EiB',
15721
+ 'ZiB',
15722
+ 'YiB',
15723
+ ];
15724
+
15725
+ const BIT_UNITS = [
15726
+ 'b',
15727
+ 'kbit',
15728
+ 'Mbit',
15729
+ 'Gbit',
15730
+ 'Tbit',
15731
+ 'Pbit',
15732
+ 'Ebit',
15733
+ 'Zbit',
15734
+ 'Ybit',
15735
+ ];
15736
+
15737
+ const BIBIT_UNITS = [
15738
+ 'b',
15739
+ 'kibit',
15740
+ 'Mibit',
15741
+ 'Gibit',
15742
+ 'Tibit',
15743
+ 'Pibit',
15744
+ 'Eibit',
15745
+ 'Zibit',
15746
+ 'Yibit',
15747
+ ];
15748
+
15749
+ /*
15750
+ Formats the given number using `Number#toLocaleString`.
15751
+ - If locale is a string, the value is expected to be a locale-key (for example: `de`).
15752
+ - If locale is true, the system default locale is used for translation.
15753
+ - If no value for locale is specified, the number is returned unmodified.
15754
+ */
15755
+ const toLocaleString = (number, locale, options) => {
15756
+ let result = number;
15757
+ if (typeof locale === 'string' || Array.isArray(locale)) {
15758
+ result = number.toLocaleString(locale, options);
15759
+ } else if (locale === true || options !== undefined) {
15760
+ result = number.toLocaleString(undefined, options);
15761
+ }
15762
+
15763
+ return result;
15764
+ };
15765
+
15766
+ function prettyBytes(number, options) {
15767
+ if (!Number.isFinite(number)) {
15768
+ throw new TypeError(`Expected a finite number, got ${typeof number}: ${number}`);
15769
+ }
15770
+
15771
+ options = {
15772
+ bits: false,
15773
+ binary: false,
15774
+ ...options,
15775
+ };
15776
+
15777
+ const UNITS = options.bits
15778
+ ? (options.binary ? BIBIT_UNITS : BIT_UNITS)
15779
+ : (options.binary ? BIBYTE_UNITS : BYTE_UNITS);
15780
+
15781
+ if (options.signed && number === 0) {
15782
+ return ` 0 ${UNITS[0]}`;
15783
+ }
15784
+
15785
+ const isNegative = number < 0;
15786
+ const prefix = isNegative ? '-' : (options.signed ? '+' : '');
15787
+
15788
+ if (isNegative) {
15789
+ number = -number;
15790
+ }
15791
+
15792
+ let localeOptions;
15793
+
15794
+ if (options.minimumFractionDigits !== undefined) {
15795
+ localeOptions = {minimumFractionDigits: options.minimumFractionDigits};
15796
+ }
15797
+
15798
+ if (options.maximumFractionDigits !== undefined) {
15799
+ localeOptions = {maximumFractionDigits: options.maximumFractionDigits, ...localeOptions};
15800
+ }
15801
+
15802
+ if (number < 1) {
15803
+ const numberString = toLocaleString(number, options.locale, localeOptions);
15804
+ return prefix + numberString + ' ' + UNITS[0];
15805
+ }
15806
+
15807
+ const exponent = Math.min(Math.floor(options.binary ? Math.log(number) / Math.log(1024) : Math.log10(number) / 3), UNITS.length - 1);
15808
+ number /= (options.binary ? 1024 : 1000) ** exponent;
15809
+
15810
+ if (!localeOptions) {
15811
+ number = number.toPrecision(3);
15812
+ }
15813
+
15814
+ const numberString = toLocaleString(Number(number), options.locale, localeOptions);
15815
+
15816
+ const unit = UNITS[exponent];
15817
+
15818
+ return prefix + numberString + ' ' + unit;
15819
+ }
15820
+
15643
15821
  /**
15644
15822
  * Concatenate a number of iterables to a new iterable without fully evaluating
15645
15823
  * their iterators. Useful when e.g. working with large sets or lists and when
15646
15824
  * there is a chance that the iterators will not be fully exhausted.
15647
15825
  */
15648
- function* concatLazy(...iterables) {
15826
+ function* concatLazy(iterables) {
15649
15827
  for (const iterable of iterables) {
15650
15828
  yield* iterable;
15651
15829
  }
@@ -15771,43 +15949,37 @@ function createChunks(allEntryPoints, assignedEntryPointsByModule, minChunkSize)
15771
15949
  alias: null,
15772
15950
  modules
15773
15951
  }))
15774
- : getOptimizedChunks(chunkModulesBySignature, minChunkSize);
15952
+ : getOptimizedChunks(chunkModulesBySignature, minChunkSize).map(({ modules }) => ({
15953
+ alias: null,
15954
+ modules
15955
+ }));
15775
15956
  }
15776
15957
  function getOptimizedChunks(chunkModulesBySignature, minChunkSize) {
15777
15958
  timeStart('optimize chunks', 3);
15778
- const { chunksToBeMerged, unmergeableChunks } = getMergeableChunks(chunkModulesBySignature, minChunkSize);
15779
- for (const sourceChunk of chunksToBeMerged) {
15780
- chunksToBeMerged.delete(sourceChunk);
15781
- let closestChunk = null;
15782
- let closestChunkDistance = Infinity;
15783
- const { signature, size, modules } = sourceChunk;
15784
- for (const targetChunk of concatLazy(chunksToBeMerged, unmergeableChunks)) {
15785
- const distance = getSignatureDistance(signature, targetChunk.signature, !chunksToBeMerged.has(targetChunk));
15786
- if (distance === 1) {
15787
- closestChunk = targetChunk;
15788
- break;
15789
- }
15790
- else if (distance < closestChunkDistance) {
15791
- closestChunk = targetChunk;
15792
- closestChunkDistance = distance;
15793
- }
15794
- }
15795
- if (closestChunk) {
15796
- closestChunk.modules.push(...modules);
15797
- if (chunksToBeMerged.has(closestChunk)) {
15798
- closestChunk.signature = mergeSignatures(signature, closestChunk.signature);
15799
- if ((closestChunk.size += size) > minChunkSize) {
15800
- chunksToBeMerged.delete(closestChunk);
15801
- unmergeableChunks.push(closestChunk);
15802
- }
15803
- }
15804
- }
15805
- else {
15806
- unmergeableChunks.push(sourceChunk);
15807
- }
15808
- }
15959
+ const chunkPartition = getPartitionedChunks(chunkModulesBySignature, minChunkSize);
15960
+ console.log(`Created ${chunkPartition.big.pure.size +
15961
+ chunkPartition.big.sideEffect.size +
15962
+ chunkPartition.small.pure.size +
15963
+ chunkPartition.small.sideEffect.size} chunks
15964
+ ----- pure side effects
15965
+ small ${`${chunkPartition.small.pure.size}`.padEnd(5, ' ')} ${chunkPartition.small.sideEffect.size}
15966
+ big ${`${chunkPartition.big.pure.size}`.padEnd(5, ' ')} ${chunkPartition.big.sideEffect.size}
15967
+ `);
15968
+ console.log(`Trying to find merge targets for ${chunkPartition.small.sideEffect.size} chunks smaller than ${prettyBytes(minChunkSize)} with side effects...`);
15969
+ mergeChunks(chunkPartition.small.sideEffect, [chunkPartition.small.pure, chunkPartition.big.pure], minChunkSize, chunkPartition);
15970
+ console.log(`${chunkPartition.small.sideEffect.size} chunks smaller than ${prettyBytes(minChunkSize)} with side effects remaining.\n`);
15971
+ console.log(`Trying to find merge targets for ${chunkPartition.small.pure.size} pure chunks smaller than ${prettyBytes(minChunkSize)}...`);
15972
+ mergeChunks(chunkPartition.small.pure, [chunkPartition.small.pure, chunkPartition.big.sideEffect, chunkPartition.big.pure], minChunkSize, chunkPartition);
15973
+ console.log(`${chunkPartition.small.pure.size} pure chunks smaller than ${prettyBytes(minChunkSize)} remaining.\n`);
15809
15974
  timeEnd('optimize chunks', 3);
15810
- return unmergeableChunks;
15975
+ const result = [
15976
+ ...chunkPartition.small.sideEffect,
15977
+ ...chunkPartition.small.pure,
15978
+ ...chunkPartition.big.sideEffect,
15979
+ ...chunkPartition.big.pure
15980
+ ];
15981
+ console.log(`${result.length} chunks remaining.`);
15982
+ return result;
15811
15983
  }
15812
15984
  const CHAR_DEPENDENT = 'X';
15813
15985
  const CHAR_INDEPENDENT = '_';
@@ -15829,28 +16001,76 @@ function getChunkModulesBySignature(assignedEntryPointsByModule, allEntryPoints)
15829
16001
  }
15830
16002
  return chunkModules;
15831
16003
  }
15832
- function getMergeableChunks(chunkModulesBySignature, minChunkSize) {
15833
- const chunksToBeMerged = new Set();
15834
- const unmergeableChunks = [];
15835
- const alias = null;
16004
+ function getPartitionedChunks(chunkModulesBySignature, minChunkSize) {
16005
+ const smallPureChunks = [];
16006
+ const bigPureChunks = [];
16007
+ const smallSideEffectChunks = [];
16008
+ const bigSideEffectChunks = [];
15836
16009
  for (const [signature, modules] of Object.entries(chunkModulesBySignature)) {
15837
16010
  let size = 0;
15838
- checkModules: {
15839
- for (const module of modules) {
15840
- if (module.hasEffects()) {
15841
- break checkModules;
15842
- }
15843
- size += module.magicString.toString().length;
15844
- if (size > minChunkSize) {
15845
- break checkModules;
15846
- }
16011
+ let pure = true;
16012
+ for (const module of modules) {
16013
+ pure && (pure = !module.hasEffects());
16014
+ size += module.magicString.toString().length;
16015
+ }
16016
+ (size < minChunkSize
16017
+ ? pure
16018
+ ? smallPureChunks
16019
+ : smallSideEffectChunks
16020
+ : pure
16021
+ ? bigPureChunks
16022
+ : bigSideEffectChunks).push({ modules, pure, signature, size });
16023
+ }
16024
+ for (const chunks of [
16025
+ bigPureChunks,
16026
+ bigSideEffectChunks,
16027
+ smallPureChunks,
16028
+ smallSideEffectChunks
16029
+ ]) {
16030
+ chunks.sort(compareChunks);
16031
+ }
16032
+ return {
16033
+ big: { pure: new Set(bigPureChunks), sideEffect: new Set(bigSideEffectChunks) },
16034
+ small: { pure: new Set(smallPureChunks), sideEffect: new Set(smallSideEffectChunks) }
16035
+ };
16036
+ }
16037
+ function compareChunks({ size: sizeA }, { size: sizeB }) {
16038
+ return sizeA - sizeB;
16039
+ }
16040
+ function mergeChunks(chunksToBeMerged, targetChunks, minChunkSize, chunkPartition) {
16041
+ for (const mergedChunk of chunksToBeMerged) {
16042
+ let closestChunk = null;
16043
+ let closestChunkDistance = Infinity;
16044
+ const { signature, modules, pure, size } = mergedChunk;
16045
+ for (const targetChunk of concatLazy(targetChunks)) {
16046
+ if (mergedChunk === targetChunk)
16047
+ continue;
16048
+ const distance = pure
16049
+ ? getSignatureDistance(signature, targetChunk.signature, !targetChunk.pure)
16050
+ : getSignatureDistance(targetChunk.signature, signature, true);
16051
+ if (distance === 1) {
16052
+ closestChunk = targetChunk;
16053
+ break;
16054
+ }
16055
+ else if (distance < closestChunkDistance) {
16056
+ closestChunk = targetChunk;
16057
+ closestChunkDistance = distance;
15847
16058
  }
15848
- chunksToBeMerged.add({ alias, modules, signature, size });
15849
- continue;
15850
16059
  }
15851
- unmergeableChunks.push({ alias, modules, signature, size: null });
16060
+ if (closestChunk) {
16061
+ chunksToBeMerged.delete(mergedChunk);
16062
+ getChunksInPartition(closestChunk, minChunkSize, chunkPartition).delete(closestChunk);
16063
+ closestChunk.modules.push(...modules);
16064
+ closestChunk.size += size;
16065
+ closestChunk.pure && (closestChunk.pure = pure);
16066
+ closestChunk.signature = mergeSignatures(signature, closestChunk.signature);
16067
+ getChunksInPartition(closestChunk, minChunkSize, chunkPartition).add(closestChunk);
16068
+ }
15852
16069
  }
15853
- return { chunksToBeMerged, unmergeableChunks };
16070
+ }
16071
+ function getChunksInPartition(chunk, minChunkSize, chunkPartition) {
16072
+ const subPartition = chunk.size < minChunkSize ? chunkPartition.small : chunkPartition.big;
16073
+ return chunk.pure ? subPartition.pure : subPartition.sideEffect;
15854
16074
  }
15855
16075
  function getSignatureDistance(sourceSignature, targetSignature, enforceSubset) {
15856
16076
  let distance = 0;
@@ -23477,6 +23697,7 @@ class Graph {
23477
23697
  this.acornParser = Parser.extend(...options.acornInjectPlugins);
23478
23698
  this.moduleLoader = new ModuleLoader(this, this.modulesById, this.options, this.pluginDriver);
23479
23699
  this.fileOperationQueue = new Queue(options.maxParallelFileOps);
23700
+ this.pureFunctions = getPureFunctions(options);
23480
23701
  }
23481
23702
  async build() {
23482
23703
  timeStart('generate module graph', 2);
@@ -23976,6 +24197,7 @@ const treeshakePresets = {
23976
24197
  recommended: {
23977
24198
  annotations: true,
23978
24199
  correctVarValueBeforeDeclaration: false,
24200
+ manualPureFunctions: EMPTY_ARRAY,
23979
24201
  moduleSideEffects: () => true,
23980
24202
  propertyReadSideEffects: true,
23981
24203
  tryCatchDeoptimization: true,
@@ -23984,6 +24206,7 @@ const treeshakePresets = {
23984
24206
  safest: {
23985
24207
  annotations: true,
23986
24208
  correctVarValueBeforeDeclaration: true,
24209
+ manualPureFunctions: EMPTY_ARRAY,
23987
24210
  moduleSideEffects: () => true,
23988
24211
  propertyReadSideEffects: true,
23989
24212
  tryCatchDeoptimization: true,
@@ -23992,6 +24215,7 @@ const treeshakePresets = {
23992
24215
  smallest: {
23993
24216
  annotations: true,
23994
24217
  correctVarValueBeforeDeclaration: false,
24218
+ manualPureFunctions: EMPTY_ARRAY,
23995
24219
  moduleSideEffects: () => false,
23996
24220
  propertyReadSideEffects: false,
23997
24221
  tryCatchDeoptimization: false,
@@ -24188,6 +24412,7 @@ const getTreeshake = (config) => {
24188
24412
  return {
24189
24413
  annotations: configWithPreset.annotations !== false,
24190
24414
  correctVarValueBeforeDeclaration: configWithPreset.correctVarValueBeforeDeclaration === true,
24415
+ manualPureFunctions: configWithPreset.manualPureFunctions ?? EMPTY_ARRAY,
24191
24416
  moduleSideEffects: getHasModuleSideEffects(configWithPreset.moduleSideEffects),
24192
24417
  propertyReadSideEffects: configWithPreset.propertyReadSideEffects === 'always'
24193
24418
  ? 'always'