rollup 2.71.1 → 2.73.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 v2.71.1
4
- Sat, 30 Apr 2022 13:35:44 GMT - commit f44a3a38b357c2ba80a99aca36cfd30dcfb84476
3
+ Rollup.js v2.73.0
4
+ Fri, 13 May 2022 15:50:44 GMT - commit 931a19940f58c745e9da9eae5585b551f356b2ed
5
5
 
6
6
  https://github.com/rollup/rollup
7
7
 
@@ -14,7 +14,7 @@ import { createHash as createHash$1 } from 'crypto';
14
14
  import { promises } from 'fs';
15
15
  import { EventEmitter } from 'events';
16
16
 
17
- var version$1 = "2.71.1";
17
+ var version$1 = "2.73.0";
18
18
 
19
19
  var charToInteger = {};
20
20
  var chars$1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
@@ -1521,9 +1521,16 @@ function getOrCreate(map, key, init) {
1521
1521
  }
1522
1522
 
1523
1523
  const UnknownKey = Symbol('Unknown Key');
1524
+ const UnknownNonAccessorKey = Symbol('Unknown Non-Accessor Key');
1524
1525
  const UnknownInteger = Symbol('Unknown Integer');
1525
1526
  const EMPTY_PATH = [];
1526
1527
  const UNKNOWN_PATH = [UnknownKey];
1528
+ // For deoptimizations, this means we are modifying an unknown property but did
1529
+ // not lose track of the object or are creating a setter/getter;
1530
+ // For assignment effects it means we do not check for setter/getter effects
1531
+ // but only if something is mutated that is included, which is relevant for
1532
+ // Object.defineProperty
1533
+ const UNKNOWN_NON_ACCESSOR_PATH = [UnknownNonAccessorKey];
1527
1534
  const UNKNOWN_INTEGER_PATH = [UnknownInteger];
1528
1535
  const EntitiesKey = Symbol('Entities');
1529
1536
  class PathTracker {
@@ -4580,7 +4587,7 @@ const UNDEFINED_EXPRESSION = new (class UndefinedExpression extends ExpressionEn
4580
4587
  })();
4581
4588
  const returnsUnknown = {
4582
4589
  value: {
4583
- callsArgs: null,
4590
+ hasEffectsWhenCalled: null,
4584
4591
  returns: UNKNOWN_EXPRESSION
4585
4592
  }
4586
4593
  };
@@ -4603,7 +4610,7 @@ const UNKNOWN_LITERAL_BOOLEAN = new (class UnknownBoolean extends ExpressionEnti
4603
4610
  })();
4604
4611
  const returnsBoolean = {
4605
4612
  value: {
4606
- callsArgs: null,
4613
+ hasEffectsWhenCalled: null,
4607
4614
  returns: UNKNOWN_LITERAL_BOOLEAN
4608
4615
  }
4609
4616
  };
@@ -4626,7 +4633,7 @@ const UNKNOWN_LITERAL_NUMBER = new (class UnknownNumber extends ExpressionEntity
4626
4633
  })();
4627
4634
  const returnsNumber = {
4628
4635
  value: {
4629
- callsArgs: null,
4636
+ hasEffectsWhenCalled: null,
4630
4637
  returns: UNKNOWN_LITERAL_NUMBER
4631
4638
  }
4632
4639
  };
@@ -4649,7 +4656,24 @@ const UNKNOWN_LITERAL_STRING = new (class UnknownString extends ExpressionEntity
4649
4656
  })();
4650
4657
  const returnsString = {
4651
4658
  value: {
4652
- callsArgs: null,
4659
+ hasEffectsWhenCalled: null,
4660
+ returns: UNKNOWN_LITERAL_STRING
4661
+ }
4662
+ };
4663
+ const stringReplace = {
4664
+ value: {
4665
+ hasEffectsWhenCalled(callOptions, context) {
4666
+ const arg1 = callOptions.args[1];
4667
+ return (callOptions.args.length < 2 ||
4668
+ (arg1.getLiteralValueAtPath(EMPTY_PATH, SHARED_RECURSION_TRACKER, {
4669
+ deoptimizeCache() { }
4670
+ }) === UnknownValue &&
4671
+ arg1.hasEffectsWhenCalledAtPath(EMPTY_PATH, {
4672
+ args: NO_ARGS,
4673
+ thisParam: null,
4674
+ withNew: false
4675
+ }, context)));
4676
+ },
4653
4677
  returns: UNKNOWN_LITERAL_STRING
4654
4678
  }
4655
4679
  };
@@ -4697,18 +4721,8 @@ const literalStringMembers = assembleMemberDescriptions({
4697
4721
  padEnd: returnsString,
4698
4722
  padStart: returnsString,
4699
4723
  repeat: returnsString,
4700
- replace: {
4701
- value: {
4702
- callsArgs: [1],
4703
- returns: UNKNOWN_LITERAL_STRING
4704
- }
4705
- },
4706
- replaceAll: {
4707
- value: {
4708
- callsArgs: [1],
4709
- returns: UNKNOWN_LITERAL_STRING
4710
- }
4711
- },
4724
+ replace: stringReplace,
4725
+ replaceAll: stringReplace,
4712
4726
  search: returnsNumber,
4713
4727
  slice: returnsString,
4714
4728
  small: returnsString,
@@ -4743,21 +4757,11 @@ function getLiteralMembersForValue(value) {
4743
4757
  return Object.create(null);
4744
4758
  }
4745
4759
  function hasMemberEffectWhenCalled(members, memberName, callOptions, context) {
4760
+ var _a, _b;
4746
4761
  if (typeof memberName !== 'string' || !members[memberName]) {
4747
4762
  return true;
4748
4763
  }
4749
- if (!members[memberName].callsArgs)
4750
- return false;
4751
- for (const argIndex of members[memberName].callsArgs) {
4752
- if (callOptions.args[argIndex] &&
4753
- callOptions.args[argIndex].hasEffectsWhenCalledAtPath(EMPTY_PATH, {
4754
- args: NO_ARGS,
4755
- thisParam: null,
4756
- withNew: false
4757
- }, context))
4758
- return true;
4759
- }
4760
- return false;
4764
+ return ((_b = (_a = members[memberName]).hasEffectsWhenCalled) === null || _b === void 0 ? void 0 : _b.call(_a, callOptions, context)) || false;
4761
4765
  }
4762
4766
  function getMemberReturnExpressionWhenCalled(members, memberName) {
4763
4767
  if (typeof memberName !== 'string' || !members[memberName])
@@ -5464,6 +5468,7 @@ class ObjectEntity extends ExpressionEntity {
5464
5468
  this.deoptimizedPaths = Object.create(null);
5465
5469
  this.expressionsToBeDeoptimizedByKey = Object.create(null);
5466
5470
  this.gettersByKey = Object.create(null);
5471
+ this.hasLostTrack = false;
5467
5472
  this.hasUnknownDeoptimizedInteger = false;
5468
5473
  this.hasUnknownDeoptimizedProperty = false;
5469
5474
  this.propertiesAndGettersByKey = Object.create(null);
@@ -5484,12 +5489,18 @@ class ObjectEntity extends ExpressionEntity {
5484
5489
  }
5485
5490
  }
5486
5491
  }
5487
- deoptimizeAllProperties() {
5492
+ deoptimizeAllProperties(noAccessors) {
5488
5493
  var _a;
5489
- if (this.hasUnknownDeoptimizedProperty) {
5494
+ const isDeoptimized = this.hasLostTrack || this.hasUnknownDeoptimizedProperty;
5495
+ if (noAccessors) {
5496
+ this.hasUnknownDeoptimizedProperty = true;
5497
+ }
5498
+ else {
5499
+ this.hasLostTrack = true;
5500
+ }
5501
+ if (isDeoptimized) {
5490
5502
  return;
5491
5503
  }
5492
- this.hasUnknownDeoptimizedProperty = true;
5493
5504
  for (const properties of Object.values(this.propertiesAndGettersByKey).concat(Object.values(this.settersByKey))) {
5494
5505
  for (const property of properties) {
5495
5506
  property.deoptimizePath(UNKNOWN_PATH);
@@ -5500,7 +5511,9 @@ class ObjectEntity extends ExpressionEntity {
5500
5511
  this.deoptimizeCachedEntities();
5501
5512
  }
5502
5513
  deoptimizeIntegerProperties() {
5503
- if (this.hasUnknownDeoptimizedProperty || this.hasUnknownDeoptimizedInteger) {
5514
+ if (this.hasLostTrack ||
5515
+ this.hasUnknownDeoptimizedProperty ||
5516
+ this.hasUnknownDeoptimizedInteger) {
5504
5517
  return;
5505
5518
  }
5506
5519
  this.hasUnknownDeoptimizedInteger = true;
@@ -5513,17 +5526,19 @@ class ObjectEntity extends ExpressionEntity {
5513
5526
  }
5514
5527
  this.deoptimizeCachedIntegerEntities();
5515
5528
  }
5529
+ // Assumption: If only a specific path is deoptimized, no accessors are created
5516
5530
  deoptimizePath(path) {
5517
5531
  var _a;
5518
- if (this.hasUnknownDeoptimizedProperty || this.immutable)
5532
+ if (this.hasLostTrack || this.immutable) {
5519
5533
  return;
5534
+ }
5520
5535
  const key = path[0];
5521
5536
  if (path.length === 1) {
5522
5537
  if (typeof key !== 'string') {
5523
5538
  if (key === UnknownInteger) {
5524
5539
  return this.deoptimizeIntegerProperties();
5525
5540
  }
5526
- return this.deoptimizeAllProperties();
5541
+ return this.deoptimizeAllProperties(key === UnknownNonAccessorKey);
5527
5542
  }
5528
5543
  if (!this.deoptimizedPaths[key]) {
5529
5544
  this.deoptimizedPaths[key] = true;
@@ -5543,16 +5558,16 @@ class ObjectEntity extends ExpressionEntity {
5543
5558
  : this.allProperties) {
5544
5559
  property.deoptimizePath(subPath);
5545
5560
  }
5546
- (_a = this.prototypeExpression) === null || _a === void 0 ? void 0 : _a.deoptimizePath(path.length === 1 ? [UnknownKey, UnknownKey] : path);
5561
+ (_a = this.prototypeExpression) === null || _a === void 0 ? void 0 : _a.deoptimizePath(path.length === 1 ? [...path, UnknownKey] : path);
5547
5562
  }
5548
5563
  deoptimizeThisOnEventAtPath(event, path, thisParameter, recursionTracker) {
5549
5564
  var _a;
5550
5565
  const [key, ...subPath] = path;
5551
- if (this.hasUnknownDeoptimizedProperty ||
5566
+ if (this.hasLostTrack ||
5552
5567
  // single paths that are deoptimized will not become getters or setters
5553
5568
  ((event === EVENT_CALLED || path.length > 1) &&
5554
- typeof key === 'string' &&
5555
- this.deoptimizedPaths[key])) {
5569
+ (this.hasUnknownDeoptimizedProperty ||
5570
+ (typeof key === 'string' && this.deoptimizedPaths[key])))) {
5556
5571
  thisParameter.deoptimizePath(UNKNOWN_PATH);
5557
5572
  return;
5558
5573
  }
@@ -5650,7 +5665,7 @@ class ObjectEntity extends ExpressionEntity {
5650
5665
  }
5651
5666
  return true;
5652
5667
  }
5653
- if (this.hasUnknownDeoptimizedProperty)
5668
+ if (this.hasLostTrack)
5654
5669
  return true;
5655
5670
  if (typeof key === 'string') {
5656
5671
  if (this.propertiesAndGettersByKey[key]) {
@@ -5697,9 +5712,10 @@ class ObjectEntity extends ExpressionEntity {
5697
5712
  }
5698
5713
  return true;
5699
5714
  }
5700
- if (this.hasUnknownDeoptimizedProperty)
5715
+ if (key === UnknownNonAccessorKey)
5716
+ return false;
5717
+ if (this.hasLostTrack)
5701
5718
  return true;
5702
- // We do not need to test for unknown properties as in that case, hasUnknownDeoptimizedProperty is true
5703
5719
  if (typeof key === 'string') {
5704
5720
  if (this.propertiesAndSettersByKey[key]) {
5705
5721
  const setters = this.settersByKey[key];
@@ -5717,6 +5733,14 @@ class ObjectEntity extends ExpressionEntity {
5717
5733
  }
5718
5734
  }
5719
5735
  }
5736
+ else {
5737
+ for (const setters of Object.values(this.settersByKey).concat([this.unmatchableSetters])) {
5738
+ for (const setter of setters) {
5739
+ if (setter.hasEffectsWhenAssignedAtPath(subPath, context))
5740
+ return true;
5741
+ }
5742
+ }
5743
+ }
5720
5744
  if (this.prototypeExpression) {
5721
5745
  return this.prototypeExpression.hasEffectsWhenAssignedAtPath(path, context);
5722
5746
  }
@@ -5800,7 +5824,8 @@ class ObjectEntity extends ExpressionEntity {
5800
5824
  }
5801
5825
  }
5802
5826
  getMemberExpression(key) {
5803
- if (this.hasUnknownDeoptimizedProperty ||
5827
+ if (this.hasLostTrack ||
5828
+ this.hasUnknownDeoptimizedProperty ||
5804
5829
  typeof key !== 'string' ||
5805
5830
  (this.hasUnknownDeoptimizedInteger && INTEGER_REG_EXP.test(key)) ||
5806
5831
  this.deoptimizedPaths[key]) {
@@ -6181,7 +6206,7 @@ class LocalVariable extends Variable {
6181
6206
  if (this.isReassigned)
6182
6207
  return true;
6183
6208
  return (this.init &&
6184
- !context.accessed.trackEntityAtPathAndGetIfTracked(path, this) &&
6209
+ !context.assigned.trackEntityAtPathAndGetIfTracked(path, this) &&
6185
6210
  this.init.hasEffectsWhenAssignedAtPath(path, context));
6186
6211
  }
6187
6212
  hasEffectsWhenCalledAtPath(path, callOptions, context) {
@@ -6466,323 +6491,89 @@ class ReturnValueScope extends ParameterScope {
6466
6491
  }
6467
6492
  }
6468
6493
 
6469
- function treeshakeNode(node, code, start, end) {
6470
- code.remove(start, end);
6471
- if (node.annotations) {
6472
- for (const annotation of node.annotations) {
6473
- if (annotation.start < start) {
6474
- code.remove(annotation.start, annotation.end);
6475
- }
6476
- else {
6477
- return;
6478
- }
6479
- }
6480
- }
6481
- }
6482
- function removeAnnotations(node, code) {
6483
- if (!node.annotations && node.parent.type === ExpressionStatement$1) {
6484
- node = node.parent;
6485
- }
6486
- if (node.annotations) {
6487
- for (const annotation of node.annotations) {
6488
- code.remove(annotation.start, annotation.end);
6489
- }
6490
- }
6491
- }
6494
+ //@ts-check
6495
+ /** @typedef { import('estree').Node} Node */
6496
+ /** @typedef {Node | {
6497
+ * type: 'PropertyDefinition';
6498
+ * computed: boolean;
6499
+ * value: Node
6500
+ * }} NodeWithPropertyDefinition */
6492
6501
 
6493
- const NO_SEMICOLON = { isNoStatement: true };
6494
- // This assumes there are only white-space and comments between start and the string we are looking for
6495
- function findFirstOccurrenceOutsideComment(code, searchString, start = 0) {
6496
- let searchPos, charCodeAfterSlash;
6497
- searchPos = code.indexOf(searchString, start);
6498
- while (true) {
6499
- start = code.indexOf('/', start);
6500
- if (start === -1 || start >= searchPos)
6501
- return searchPos;
6502
- charCodeAfterSlash = code.charCodeAt(++start);
6503
- ++start;
6504
- // With our assumption, '/' always starts a comment. Determine comment type:
6505
- start =
6506
- charCodeAfterSlash === 47 /*"/"*/
6507
- ? code.indexOf('\n', start) + 1
6508
- : code.indexOf('*/', start) + 2;
6509
- if (start > searchPos) {
6510
- searchPos = code.indexOf(searchString, start);
6511
- }
6512
- }
6513
- }
6514
- const NON_WHITESPACE = /\S/g;
6515
- function findNonWhiteSpace(code, index) {
6516
- NON_WHITESPACE.lastIndex = index;
6517
- const result = NON_WHITESPACE.exec(code);
6518
- return result.index;
6519
- }
6520
- // This assumes "code" only contains white-space and comments
6521
- // Returns position of line-comment if applicable
6522
- function findFirstLineBreakOutsideComment(code) {
6523
- let lineBreakPos, charCodeAfterSlash, start = 0;
6524
- lineBreakPos = code.indexOf('\n', start);
6525
- while (true) {
6526
- start = code.indexOf('/', start);
6527
- if (start === -1 || start > lineBreakPos)
6528
- return [lineBreakPos, lineBreakPos + 1];
6529
- // With our assumption, '/' always starts a comment. Determine comment type:
6530
- charCodeAfterSlash = code.charCodeAt(start + 1);
6531
- if (charCodeAfterSlash === 47 /*"/"*/)
6532
- return [start, lineBreakPos + 1];
6533
- start = code.indexOf('*/', start + 3) + 2;
6534
- if (start > lineBreakPos) {
6535
- lineBreakPos = code.indexOf('\n', start);
6536
- }
6537
- }
6502
+ /**
6503
+ *
6504
+ * @param {NodeWithPropertyDefinition} node
6505
+ * @param {NodeWithPropertyDefinition} parent
6506
+ * @returns boolean
6507
+ */
6508
+ function is_reference (node, parent) {
6509
+ if (node.type === 'MemberExpression') {
6510
+ return !node.computed && is_reference(node.object, node);
6511
+ }
6512
+
6513
+ if (node.type === 'Identifier') {
6514
+ if (!parent) return true;
6515
+
6516
+ switch (parent.type) {
6517
+ // disregard `bar` in `foo.bar`
6518
+ case 'MemberExpression': return parent.computed || node === parent.object;
6519
+
6520
+ // disregard the `foo` in `class {foo(){}}` but keep it in `class {[foo](){}}`
6521
+ case 'MethodDefinition': return parent.computed;
6522
+
6523
+ // disregard the `foo` in `class {foo=bar}` but keep it in `class {[foo]=bar}` and `class {bar=foo}`
6524
+ case 'PropertyDefinition': return parent.computed || node === parent.value;
6525
+
6526
+ // disregard the `bar` in `{ bar: foo }`, but keep it in `{ [bar]: foo }`
6527
+ case 'Property': return parent.computed || node === parent.value;
6528
+
6529
+ // disregard the `bar` in `export { foo as bar }` or
6530
+ // the foo in `import { foo as bar }`
6531
+ case 'ExportSpecifier':
6532
+ case 'ImportSpecifier': return node === parent.local;
6533
+
6534
+ // disregard the `foo` in `foo: while (...) { ... break foo; ... continue foo;}`
6535
+ case 'LabeledStatement':
6536
+ case 'BreakStatement':
6537
+ case 'ContinueStatement': return false;
6538
+ default: return true;
6539
+ }
6540
+ }
6541
+
6542
+ return false;
6538
6543
  }
6539
- function renderStatementList(statements, code, start, end, options) {
6540
- let currentNode, currentNodeStart, currentNodeNeedsBoundaries, nextNodeStart;
6541
- let nextNode = statements[0];
6542
- let nextNodeNeedsBoundaries = !nextNode.included || nextNode.needsBoundaries;
6543
- if (nextNodeNeedsBoundaries) {
6544
- nextNodeStart =
6545
- start + findFirstLineBreakOutsideComment(code.original.slice(start, nextNode.start))[1];
6546
- }
6547
- for (let nextIndex = 1; nextIndex <= statements.length; nextIndex++) {
6548
- currentNode = nextNode;
6549
- currentNodeStart = nextNodeStart;
6550
- currentNodeNeedsBoundaries = nextNodeNeedsBoundaries;
6551
- nextNode = statements[nextIndex];
6552
- nextNodeNeedsBoundaries =
6553
- nextNode === undefined ? false : !nextNode.included || nextNode.needsBoundaries;
6554
- if (currentNodeNeedsBoundaries || nextNodeNeedsBoundaries) {
6555
- nextNodeStart =
6556
- currentNode.end +
6557
- findFirstLineBreakOutsideComment(code.original.slice(currentNode.end, nextNode === undefined ? end : nextNode.start))[1];
6558
- if (currentNode.included) {
6559
- currentNodeNeedsBoundaries
6560
- ? currentNode.render(code, options, {
6561
- end: nextNodeStart,
6562
- start: currentNodeStart
6563
- })
6564
- : currentNode.render(code, options);
6565
- }
6566
- else {
6567
- treeshakeNode(currentNode, code, currentNodeStart, nextNodeStart);
6568
- }
6569
- }
6570
- else {
6571
- currentNode.render(code, options);
6572
- }
6544
+
6545
+ /* eslint sort-keys: "off" */
6546
+ const ValueProperties = Symbol('Value Properties');
6547
+ const PURE = {
6548
+ hasEffectsWhenCalled() {
6549
+ return false;
6573
6550
  }
6574
- }
6575
- // This assumes that the first character is not part of the first node
6576
- function getCommaSeparatedNodesWithBoundaries(nodes, code, start, end) {
6577
- const splitUpNodes = [];
6578
- let node, nextNode, nextNodeStart, contentEnd, char;
6579
- let separator = start - 1;
6580
- for (let nextIndex = 0; nextIndex < nodes.length; nextIndex++) {
6581
- nextNode = nodes[nextIndex];
6582
- if (node !== undefined) {
6583
- separator =
6584
- node.end +
6585
- findFirstOccurrenceOutsideComment(code.original.slice(node.end, nextNode.start), ',');
6586
- }
6587
- nextNodeStart = contentEnd =
6588
- separator +
6589
- 1 +
6590
- findFirstLineBreakOutsideComment(code.original.slice(separator + 1, nextNode.start))[1];
6591
- while (((char = code.original.charCodeAt(nextNodeStart)),
6592
- char === 32 /*" "*/ || char === 9 /*"\t"*/ || char === 10 /*"\n"*/ || char === 13) /*"\r"*/)
6593
- nextNodeStart++;
6594
- if (node !== undefined) {
6595
- splitUpNodes.push({
6596
- contentEnd,
6597
- end: nextNodeStart,
6598
- node,
6599
- separator,
6600
- start
6601
- });
6602
- }
6603
- node = nextNode;
6604
- start = nextNodeStart;
6551
+ };
6552
+ const IMPURE = {
6553
+ hasEffectsWhenCalled() {
6554
+ return true;
6605
6555
  }
6606
- splitUpNodes.push({
6607
- contentEnd: end,
6608
- end,
6609
- node: node,
6610
- separator: null,
6611
- start
6612
- });
6613
- return splitUpNodes;
6614
- }
6615
- // This assumes there are only white-space and comments between start and end
6616
- function removeLineBreaks(code, start, end) {
6617
- while (true) {
6618
- const [removeStart, removeEnd] = findFirstLineBreakOutsideComment(code.original.slice(start, end));
6619
- if (removeStart === -1) {
6620
- break;
6556
+ };
6557
+ // We use shortened variables to reduce file size here
6558
+ /* OBJECT */
6559
+ const O = {
6560
+ __proto__: null,
6561
+ [ValueProperties]: IMPURE
6562
+ };
6563
+ /* PURE FUNCTION */
6564
+ const PF = {
6565
+ __proto__: null,
6566
+ [ValueProperties]: PURE
6567
+ };
6568
+ /* FUNCTION THAT MUTATES FIRST ARG WITHOUT TRIGGERING ACCESSORS */
6569
+ const MUTATES_ARG_WITHOUT_ACCESSOR = {
6570
+ __proto__: null,
6571
+ [ValueProperties]: {
6572
+ hasEffectsWhenCalled(callOptions, context) {
6573
+ return (!callOptions.args.length ||
6574
+ callOptions.args[0].hasEffectsWhenAssignedAtPath(UNKNOWN_NON_ACCESSOR_PATH, context));
6621
6575
  }
6622
- code.remove(start + removeStart, (start += removeEnd));
6623
6576
  }
6624
- }
6625
-
6626
- class BlockScope extends ChildScope {
6627
- addDeclaration(identifier, context, init, isHoisted) {
6628
- if (isHoisted) {
6629
- const variable = this.parent.addDeclaration(identifier, context, init, isHoisted);
6630
- // Necessary to make sure the init is deoptimized for conditional declarations.
6631
- // We cannot call deoptimizePath here.
6632
- variable.markInitializersForDeoptimization();
6633
- return variable;
6634
- }
6635
- else {
6636
- return super.addDeclaration(identifier, context, init, false);
6637
- }
6638
- }
6639
- }
6640
-
6641
- class ExpressionStatement extends NodeBase {
6642
- initialise() {
6643
- if (this.directive &&
6644
- this.directive !== 'use strict' &&
6645
- this.parent.type === Program$1) {
6646
- this.context.warn(
6647
- // This is necessary, because either way (deleting or not) can lead to errors.
6648
- {
6649
- code: 'MODULE_LEVEL_DIRECTIVE',
6650
- message: `Module level directives cause errors when bundled, '${this.directive}' was ignored.`
6651
- }, this.start);
6652
- }
6653
- }
6654
- render(code, options) {
6655
- super.render(code, options);
6656
- if (this.included)
6657
- this.insertSemicolon(code);
6658
- }
6659
- shouldBeIncluded(context) {
6660
- if (this.directive && this.directive !== 'use strict')
6661
- return this.parent.type !== Program$1;
6662
- return super.shouldBeIncluded(context);
6663
- }
6664
- }
6665
-
6666
- class BlockStatement extends NodeBase {
6667
- constructor() {
6668
- super(...arguments);
6669
- this.directlyIncluded = false;
6670
- }
6671
- addImplicitReturnExpressionToScope() {
6672
- const lastStatement = this.body[this.body.length - 1];
6673
- if (!lastStatement || lastStatement.type !== ReturnStatement$1) {
6674
- this.scope.addReturnExpression(UNKNOWN_EXPRESSION);
6675
- }
6676
- }
6677
- createScope(parentScope) {
6678
- this.scope = this.parent.preventChildBlockScope
6679
- ? parentScope
6680
- : new BlockScope(parentScope);
6681
- }
6682
- hasEffects(context) {
6683
- if (this.deoptimizeBody)
6684
- return true;
6685
- for (const node of this.body) {
6686
- if (context.brokenFlow)
6687
- break;
6688
- if (node.hasEffects(context))
6689
- return true;
6690
- }
6691
- return false;
6692
- }
6693
- include(context, includeChildrenRecursively) {
6694
- if (!(this.deoptimizeBody && this.directlyIncluded)) {
6695
- this.included = true;
6696
- this.directlyIncluded = true;
6697
- if (this.deoptimizeBody)
6698
- includeChildrenRecursively = true;
6699
- for (const node of this.body) {
6700
- if (includeChildrenRecursively || node.shouldBeIncluded(context))
6701
- node.include(context, includeChildrenRecursively);
6702
- }
6703
- }
6704
- }
6705
- initialise() {
6706
- const firstBodyStatement = this.body[0];
6707
- this.deoptimizeBody =
6708
- firstBodyStatement instanceof ExpressionStatement &&
6709
- firstBodyStatement.directive === 'use asm';
6710
- }
6711
- render(code, options) {
6712
- if (this.body.length) {
6713
- renderStatementList(this.body, code, this.start + 1, this.end - 1, options);
6714
- }
6715
- else {
6716
- super.render(code, options);
6717
- }
6718
- }
6719
- }
6720
-
6721
- //@ts-check
6722
- /** @typedef { import('estree').Node} Node */
6723
- /** @typedef {Node | {
6724
- * type: 'PropertyDefinition';
6725
- * computed: boolean;
6726
- * value: Node
6727
- * }} NodeWithPropertyDefinition */
6728
-
6729
- /**
6730
- *
6731
- * @param {NodeWithPropertyDefinition} node
6732
- * @param {NodeWithPropertyDefinition} parent
6733
- * @returns boolean
6734
- */
6735
- function is_reference (node, parent) {
6736
- if (node.type === 'MemberExpression') {
6737
- return !node.computed && is_reference(node.object, node);
6738
- }
6739
-
6740
- if (node.type === 'Identifier') {
6741
- if (!parent) return true;
6742
-
6743
- switch (parent.type) {
6744
- // disregard `bar` in `foo.bar`
6745
- case 'MemberExpression': return parent.computed || node === parent.object;
6746
-
6747
- // disregard the `foo` in `class {foo(){}}` but keep it in `class {[foo](){}}`
6748
- case 'MethodDefinition': return parent.computed;
6749
-
6750
- // disregard the `foo` in `class {foo=bar}` but keep it in `class {[foo]=bar}` and `class {bar=foo}`
6751
- case 'PropertyDefinition': return parent.computed || node === parent.value;
6752
-
6753
- // disregard the `bar` in `{ bar: foo }`, but keep it in `{ [bar]: foo }`
6754
- case 'Property': return parent.computed || node === parent.value;
6755
-
6756
- // disregard the `bar` in `export { foo as bar }` or
6757
- // the foo in `import { foo as bar }`
6758
- case 'ExportSpecifier':
6759
- case 'ImportSpecifier': return node === parent.local;
6760
-
6761
- // disregard the `foo` in `foo: while (...) { ... break foo; ... continue foo;}`
6762
- case 'LabeledStatement':
6763
- case 'BreakStatement':
6764
- case 'ContinueStatement': return false;
6765
- default: return true;
6766
- }
6767
- }
6768
-
6769
- return false;
6770
- }
6771
-
6772
- /* eslint sort-keys: "off" */
6773
- const ValueProperties = Symbol('Value Properties');
6774
- const PURE = { pure: true };
6775
- const IMPURE = { pure: false };
6776
- // We use shortened variables to reduce file size here
6777
- /* OBJECT */
6778
- const O = {
6779
- __proto__: null,
6780
- [ValueProperties]: IMPURE
6781
- };
6782
- /* PURE FUNCTION */
6783
- const PF = {
6784
- __proto__: null,
6785
- [ValueProperties]: PURE
6786
6577
  };
6787
6578
  /* CONSTRUCTOR */
6788
6579
  const C = {
@@ -6922,6 +6713,11 @@ const knownGlobals = {
6922
6713
  __proto__: null,
6923
6714
  [ValueProperties]: PURE,
6924
6715
  create: PF,
6716
+ // Technically those can throw in certain situations, but we ignore this as
6717
+ // code that relies on this will hopefully wrap this in a try-catch, which
6718
+ // deoptimizes everything anyway
6719
+ defineProperty: MUTATES_ARG_WITHOUT_ACCESSOR,
6720
+ defineProperties: MUTATES_ARG_WITHOUT_ACCESSOR,
6925
6721
  getOwnPropertyDescriptor: PF,
6926
6722
  getOwnPropertyNames: PF,
6927
6723
  getOwnPropertySymbols: PF,
@@ -7605,27 +7401,24 @@ function getGlobalAtPath(path) {
7605
7401
  }
7606
7402
  return currentGlobal[ValueProperties];
7607
7403
  }
7608
- function isPureGlobal(path) {
7609
- const globalAtPath = getGlobalAtPath(path);
7610
- return globalAtPath !== null && globalAtPath.pure;
7611
- }
7612
- function isGlobalMember(path) {
7613
- if (path.length === 1) {
7614
- return path[0] === 'undefined' || getGlobalAtPath(path) !== null;
7615
- }
7616
- return getGlobalAtPath(path.slice(0, -1)) !== null;
7617
- }
7618
7404
 
7619
7405
  class GlobalVariable extends Variable {
7620
7406
  constructor() {
7621
7407
  super(...arguments);
7408
+ // Ensure we use live-bindings for globals as we do not know if they have
7409
+ // been reassigned
7622
7410
  this.isReassigned = true;
7623
7411
  }
7624
7412
  hasEffectsWhenAccessedAtPath(path) {
7625
- return !isGlobalMember([this.name, ...path]);
7413
+ if (path.length === 0) {
7414
+ // Technically, "undefined" is a global variable of sorts
7415
+ return this.name !== 'undefined' && getGlobalAtPath([this.name]) === null;
7416
+ }
7417
+ return getGlobalAtPath([this.name, ...path].slice(0, -1)) === null;
7626
7418
  }
7627
- hasEffectsWhenCalledAtPath(path) {
7628
- return !isPureGlobal([this.name, ...path]);
7419
+ hasEffectsWhenCalledAtPath(path, callOptions, context) {
7420
+ const globalAtPath = getGlobalAtPath([this.name, ...path]);
7421
+ return globalAtPath === null || globalAtPath.hasEffectsWhenCalled(callOptions, context);
7629
7422
  }
7630
7423
  }
7631
7424
 
@@ -7814,60 +7607,317 @@ function closestParentFunctionOrProgram(node) {
7814
7607
  return node;
7815
7608
  }
7816
7609
 
7817
- class RestElement extends NodeBase {
7818
- constructor() {
7819
- super(...arguments);
7820
- this.deoptimized = false;
7821
- this.declarationInit = null;
7822
- }
7823
- addExportedVariables(variables, exportNamesByVariable) {
7824
- this.argument.addExportedVariables(variables, exportNamesByVariable);
7825
- }
7826
- declare(kind, init) {
7827
- this.declarationInit = init;
7828
- return this.argument.declare(kind, UNKNOWN_EXPRESSION);
7829
- }
7830
- deoptimizePath(path) {
7831
- path.length === 0 && this.argument.deoptimizePath(EMPTY_PATH);
7832
- }
7833
- hasEffectsWhenAssignedAtPath(path, context) {
7834
- return path.length > 0 || this.argument.hasEffectsWhenAssignedAtPath(EMPTY_PATH, context);
7610
+ function treeshakeNode(node, code, start, end) {
7611
+ code.remove(start, end);
7612
+ if (node.annotations) {
7613
+ for (const annotation of node.annotations) {
7614
+ if (annotation.start < start) {
7615
+ code.remove(annotation.start, annotation.end);
7616
+ }
7617
+ else {
7618
+ return;
7619
+ }
7620
+ }
7835
7621
  }
7836
- markDeclarationReached() {
7837
- this.argument.markDeclarationReached();
7622
+ }
7623
+ function removeAnnotations(node, code) {
7624
+ if (!node.annotations && node.parent.type === ExpressionStatement$1) {
7625
+ node = node.parent;
7838
7626
  }
7839
- applyDeoptimizations() {
7840
- this.deoptimized = true;
7841
- if (this.declarationInit !== null) {
7842
- this.declarationInit.deoptimizePath([UnknownKey, UnknownKey]);
7843
- this.context.requestTreeshakingPass();
7627
+ if (node.annotations) {
7628
+ for (const annotation of node.annotations) {
7629
+ code.remove(annotation.start, annotation.end);
7844
7630
  }
7845
7631
  }
7846
7632
  }
7847
7633
 
7848
- class ArrowFunctionExpression extends NodeBase {
7849
- constructor() {
7850
- super(...arguments);
7851
- this.deoptimizedReturn = false;
7852
- }
7853
- createScope(parentScope) {
7854
- this.scope = new ReturnValueScope(parentScope, this.context);
7855
- }
7856
- deoptimizePath(path) {
7857
- // A reassignment of UNKNOWN_PATH is considered equivalent to having lost track
7858
- // which means the return expression needs to be reassigned
7859
- if (path.length === 1 && path[0] === UnknownKey) {
7860
- this.scope.getReturnExpression().deoptimizePath(UNKNOWN_PATH);
7634
+ const NO_SEMICOLON = { isNoStatement: true };
7635
+ // This assumes there are only white-space and comments between start and the string we are looking for
7636
+ function findFirstOccurrenceOutsideComment(code, searchString, start = 0) {
7637
+ let searchPos, charCodeAfterSlash;
7638
+ searchPos = code.indexOf(searchString, start);
7639
+ while (true) {
7640
+ start = code.indexOf('/', start);
7641
+ if (start === -1 || start >= searchPos)
7642
+ return searchPos;
7643
+ charCodeAfterSlash = code.charCodeAt(++start);
7644
+ ++start;
7645
+ // With our assumption, '/' always starts a comment. Determine comment type:
7646
+ start =
7647
+ charCodeAfterSlash === 47 /*"/"*/
7648
+ ? code.indexOf('\n', start) + 1
7649
+ : code.indexOf('*/', start) + 2;
7650
+ if (start > searchPos) {
7651
+ searchPos = code.indexOf(searchString, start);
7861
7652
  }
7862
7653
  }
7863
- // Arrow functions do not mutate their context
7864
- deoptimizeThisOnEventAtPath() { }
7865
- getReturnExpressionWhenCalledAtPath(path) {
7866
- if (path.length !== 0) {
7867
- return UNKNOWN_EXPRESSION;
7654
+ }
7655
+ const NON_WHITESPACE = /\S/g;
7656
+ function findNonWhiteSpace(code, index) {
7657
+ NON_WHITESPACE.lastIndex = index;
7658
+ const result = NON_WHITESPACE.exec(code);
7659
+ return result.index;
7660
+ }
7661
+ // This assumes "code" only contains white-space and comments
7662
+ // Returns position of line-comment if applicable
7663
+ function findFirstLineBreakOutsideComment(code) {
7664
+ let lineBreakPos, charCodeAfterSlash, start = 0;
7665
+ lineBreakPos = code.indexOf('\n', start);
7666
+ while (true) {
7667
+ start = code.indexOf('/', start);
7668
+ if (start === -1 || start > lineBreakPos)
7669
+ return [lineBreakPos, lineBreakPos + 1];
7670
+ // With our assumption, '/' always starts a comment. Determine comment type:
7671
+ charCodeAfterSlash = code.charCodeAt(start + 1);
7672
+ if (charCodeAfterSlash === 47 /*"/"*/)
7673
+ return [start, lineBreakPos + 1];
7674
+ start = code.indexOf('*/', start + 3) + 2;
7675
+ if (start > lineBreakPos) {
7676
+ lineBreakPos = code.indexOf('\n', start);
7868
7677
  }
7869
- if (this.async) {
7870
- if (!this.deoptimizedReturn) {
7678
+ }
7679
+ }
7680
+ function renderStatementList(statements, code, start, end, options) {
7681
+ let currentNode, currentNodeStart, currentNodeNeedsBoundaries, nextNodeStart;
7682
+ let nextNode = statements[0];
7683
+ let nextNodeNeedsBoundaries = !nextNode.included || nextNode.needsBoundaries;
7684
+ if (nextNodeNeedsBoundaries) {
7685
+ nextNodeStart =
7686
+ start + findFirstLineBreakOutsideComment(code.original.slice(start, nextNode.start))[1];
7687
+ }
7688
+ for (let nextIndex = 1; nextIndex <= statements.length; nextIndex++) {
7689
+ currentNode = nextNode;
7690
+ currentNodeStart = nextNodeStart;
7691
+ currentNodeNeedsBoundaries = nextNodeNeedsBoundaries;
7692
+ nextNode = statements[nextIndex];
7693
+ nextNodeNeedsBoundaries =
7694
+ nextNode === undefined ? false : !nextNode.included || nextNode.needsBoundaries;
7695
+ if (currentNodeNeedsBoundaries || nextNodeNeedsBoundaries) {
7696
+ nextNodeStart =
7697
+ currentNode.end +
7698
+ findFirstLineBreakOutsideComment(code.original.slice(currentNode.end, nextNode === undefined ? end : nextNode.start))[1];
7699
+ if (currentNode.included) {
7700
+ currentNodeNeedsBoundaries
7701
+ ? currentNode.render(code, options, {
7702
+ end: nextNodeStart,
7703
+ start: currentNodeStart
7704
+ })
7705
+ : currentNode.render(code, options);
7706
+ }
7707
+ else {
7708
+ treeshakeNode(currentNode, code, currentNodeStart, nextNodeStart);
7709
+ }
7710
+ }
7711
+ else {
7712
+ currentNode.render(code, options);
7713
+ }
7714
+ }
7715
+ }
7716
+ // This assumes that the first character is not part of the first node
7717
+ function getCommaSeparatedNodesWithBoundaries(nodes, code, start, end) {
7718
+ const splitUpNodes = [];
7719
+ let node, nextNode, nextNodeStart, contentEnd, char;
7720
+ let separator = start - 1;
7721
+ for (let nextIndex = 0; nextIndex < nodes.length; nextIndex++) {
7722
+ nextNode = nodes[nextIndex];
7723
+ if (node !== undefined) {
7724
+ separator =
7725
+ node.end +
7726
+ findFirstOccurrenceOutsideComment(code.original.slice(node.end, nextNode.start), ',');
7727
+ }
7728
+ nextNodeStart = contentEnd =
7729
+ separator +
7730
+ 1 +
7731
+ findFirstLineBreakOutsideComment(code.original.slice(separator + 1, nextNode.start))[1];
7732
+ while (((char = code.original.charCodeAt(nextNodeStart)),
7733
+ char === 32 /*" "*/ || char === 9 /*"\t"*/ || char === 10 /*"\n"*/ || char === 13) /*"\r"*/)
7734
+ nextNodeStart++;
7735
+ if (node !== undefined) {
7736
+ splitUpNodes.push({
7737
+ contentEnd,
7738
+ end: nextNodeStart,
7739
+ node,
7740
+ separator,
7741
+ start
7742
+ });
7743
+ }
7744
+ node = nextNode;
7745
+ start = nextNodeStart;
7746
+ }
7747
+ splitUpNodes.push({
7748
+ contentEnd: end,
7749
+ end,
7750
+ node: node,
7751
+ separator: null,
7752
+ start
7753
+ });
7754
+ return splitUpNodes;
7755
+ }
7756
+ // This assumes there are only white-space and comments between start and end
7757
+ function removeLineBreaks(code, start, end) {
7758
+ while (true) {
7759
+ const [removeStart, removeEnd] = findFirstLineBreakOutsideComment(code.original.slice(start, end));
7760
+ if (removeStart === -1) {
7761
+ break;
7762
+ }
7763
+ code.remove(start + removeStart, (start += removeEnd));
7764
+ }
7765
+ }
7766
+
7767
+ class BlockScope extends ChildScope {
7768
+ addDeclaration(identifier, context, init, isHoisted) {
7769
+ if (isHoisted) {
7770
+ const variable = this.parent.addDeclaration(identifier, context, init, isHoisted);
7771
+ // Necessary to make sure the init is deoptimized for conditional declarations.
7772
+ // We cannot call deoptimizePath here.
7773
+ variable.markInitializersForDeoptimization();
7774
+ return variable;
7775
+ }
7776
+ else {
7777
+ return super.addDeclaration(identifier, context, init, false);
7778
+ }
7779
+ }
7780
+ }
7781
+
7782
+ class ExpressionStatement extends NodeBase {
7783
+ initialise() {
7784
+ if (this.directive &&
7785
+ this.directive !== 'use strict' &&
7786
+ this.parent.type === Program$1) {
7787
+ this.context.warn(
7788
+ // This is necessary, because either way (deleting or not) can lead to errors.
7789
+ {
7790
+ code: 'MODULE_LEVEL_DIRECTIVE',
7791
+ message: `Module level directives cause errors when bundled, '${this.directive}' was ignored.`
7792
+ }, this.start);
7793
+ }
7794
+ }
7795
+ render(code, options) {
7796
+ super.render(code, options);
7797
+ if (this.included)
7798
+ this.insertSemicolon(code);
7799
+ }
7800
+ shouldBeIncluded(context) {
7801
+ if (this.directive && this.directive !== 'use strict')
7802
+ return this.parent.type !== Program$1;
7803
+ return super.shouldBeIncluded(context);
7804
+ }
7805
+ }
7806
+
7807
+ class BlockStatement extends NodeBase {
7808
+ constructor() {
7809
+ super(...arguments);
7810
+ this.directlyIncluded = false;
7811
+ }
7812
+ addImplicitReturnExpressionToScope() {
7813
+ const lastStatement = this.body[this.body.length - 1];
7814
+ if (!lastStatement || lastStatement.type !== ReturnStatement$1) {
7815
+ this.scope.addReturnExpression(UNKNOWN_EXPRESSION);
7816
+ }
7817
+ }
7818
+ createScope(parentScope) {
7819
+ this.scope = this.parent.preventChildBlockScope
7820
+ ? parentScope
7821
+ : new BlockScope(parentScope);
7822
+ }
7823
+ hasEffects(context) {
7824
+ if (this.deoptimizeBody)
7825
+ return true;
7826
+ for (const node of this.body) {
7827
+ if (context.brokenFlow)
7828
+ break;
7829
+ if (node.hasEffects(context))
7830
+ return true;
7831
+ }
7832
+ return false;
7833
+ }
7834
+ include(context, includeChildrenRecursively) {
7835
+ if (!(this.deoptimizeBody && this.directlyIncluded)) {
7836
+ this.included = true;
7837
+ this.directlyIncluded = true;
7838
+ if (this.deoptimizeBody)
7839
+ includeChildrenRecursively = true;
7840
+ for (const node of this.body) {
7841
+ if (includeChildrenRecursively || node.shouldBeIncluded(context))
7842
+ node.include(context, includeChildrenRecursively);
7843
+ }
7844
+ }
7845
+ }
7846
+ initialise() {
7847
+ const firstBodyStatement = this.body[0];
7848
+ this.deoptimizeBody =
7849
+ firstBodyStatement instanceof ExpressionStatement &&
7850
+ firstBodyStatement.directive === 'use asm';
7851
+ }
7852
+ render(code, options) {
7853
+ if (this.body.length) {
7854
+ renderStatementList(this.body, code, this.start + 1, this.end - 1, options);
7855
+ }
7856
+ else {
7857
+ super.render(code, options);
7858
+ }
7859
+ }
7860
+ }
7861
+
7862
+ class RestElement extends NodeBase {
7863
+ constructor() {
7864
+ super(...arguments);
7865
+ this.deoptimized = false;
7866
+ this.declarationInit = null;
7867
+ }
7868
+ addExportedVariables(variables, exportNamesByVariable) {
7869
+ this.argument.addExportedVariables(variables, exportNamesByVariable);
7870
+ }
7871
+ declare(kind, init) {
7872
+ this.declarationInit = init;
7873
+ return this.argument.declare(kind, UNKNOWN_EXPRESSION);
7874
+ }
7875
+ deoptimizePath(path) {
7876
+ path.length === 0 && this.argument.deoptimizePath(EMPTY_PATH);
7877
+ }
7878
+ hasEffectsWhenAssignedAtPath(path, context) {
7879
+ return path.length > 0 || this.argument.hasEffectsWhenAssignedAtPath(EMPTY_PATH, context);
7880
+ }
7881
+ markDeclarationReached() {
7882
+ this.argument.markDeclarationReached();
7883
+ }
7884
+ applyDeoptimizations() {
7885
+ this.deoptimized = true;
7886
+ if (this.declarationInit !== null) {
7887
+ this.declarationInit.deoptimizePath([UnknownKey, UnknownKey]);
7888
+ this.context.requestTreeshakingPass();
7889
+ }
7890
+ }
7891
+ }
7892
+
7893
+ class FunctionBase extends NodeBase {
7894
+ constructor() {
7895
+ super(...arguments);
7896
+ this.objectEntity = null;
7897
+ this.deoptimizedReturn = false;
7898
+ }
7899
+ deoptimizePath(path) {
7900
+ this.getObjectEntity().deoptimizePath(path);
7901
+ if (path.length === 1 && path[0] === UnknownKey) {
7902
+ // A reassignment of UNKNOWN_PATH is considered equivalent to having lost track
7903
+ // which means the return expression needs to be reassigned
7904
+ this.scope.getReturnExpression().deoptimizePath(UNKNOWN_PATH);
7905
+ }
7906
+ }
7907
+ deoptimizeThisOnEventAtPath(event, path, thisParameter, recursionTracker) {
7908
+ if (path.length > 0) {
7909
+ this.getObjectEntity().deoptimizeThisOnEventAtPath(event, path, thisParameter, recursionTracker);
7910
+ }
7911
+ }
7912
+ getLiteralValueAtPath(path, recursionTracker, origin) {
7913
+ return this.getObjectEntity().getLiteralValueAtPath(path, recursionTracker, origin);
7914
+ }
7915
+ getReturnExpressionWhenCalledAtPath(path, callOptions, recursionTracker, origin) {
7916
+ if (path.length > 0) {
7917
+ return this.getObjectEntity().getReturnExpressionWhenCalledAtPath(path, callOptions, recursionTracker, origin);
7918
+ }
7919
+ if (this.async) {
7920
+ if (!this.deoptimizedReturn) {
7871
7921
  this.deoptimizedReturn = true;
7872
7922
  this.scope.getReturnExpression().deoptimizePath(UNKNOWN_PATH);
7873
7923
  this.context.requestTreeshakingPass();
@@ -7876,18 +7926,16 @@ class ArrowFunctionExpression extends NodeBase {
7876
7926
  }
7877
7927
  return this.scope.getReturnExpression();
7878
7928
  }
7879
- hasEffects() {
7880
- return false;
7881
- }
7882
- hasEffectsWhenAccessedAtPath(path) {
7883
- return path.length > 1;
7929
+ hasEffectsWhenAccessedAtPath(path, context) {
7930
+ return this.getObjectEntity().hasEffectsWhenAccessedAtPath(path, context);
7884
7931
  }
7885
- hasEffectsWhenAssignedAtPath(path) {
7886
- return path.length > 1;
7932
+ hasEffectsWhenAssignedAtPath(path, context) {
7933
+ return this.getObjectEntity().hasEffectsWhenAssignedAtPath(path, context);
7887
7934
  }
7888
- hasEffectsWhenCalledAtPath(path, _callOptions, context) {
7889
- if (path.length > 0)
7890
- return true;
7935
+ hasEffectsWhenCalledAtPath(path, callOptions, context) {
7936
+ if (path.length > 0) {
7937
+ return this.getObjectEntity().hasEffectsWhenCalledAtPath(path, callOptions, context);
7938
+ }
7891
7939
  if (this.async) {
7892
7940
  const { propertyReadSideEffects } = this.context.options
7893
7941
  .treeshake;
@@ -7903,26 +7951,10 @@ class ArrowFunctionExpression extends NodeBase {
7903
7951
  if (param.hasEffects(context))
7904
7952
  return true;
7905
7953
  }
7906
- const { ignore, brokenFlow } = context;
7907
- context.ignore = {
7908
- breaks: false,
7909
- continues: false,
7910
- labels: new Set(),
7911
- returnYield: true
7912
- };
7913
- if (this.body.hasEffects(context))
7914
- return true;
7915
- context.ignore = ignore;
7916
- context.brokenFlow = brokenFlow;
7917
7954
  return false;
7918
7955
  }
7919
7956
  include(context, includeChildrenRecursively) {
7920
7957
  this.included = true;
7921
- for (const param of this.params) {
7922
- if (!(param instanceof Identifier)) {
7923
- param.include(context, includeChildrenRecursively);
7924
- }
7925
- }
7926
7958
  const { brokenFlow } = context;
7927
7959
  context.brokenFlow = BROKEN_FLOW_NONE;
7928
7960
  this.body.include(context, includeChildrenRecursively);
@@ -7947,7 +7979,50 @@ class ArrowFunctionExpression extends NodeBase {
7947
7979
  super.parseNode(esTreeNode);
7948
7980
  }
7949
7981
  }
7950
- ArrowFunctionExpression.prototype.preventChildBlockScope = true;
7982
+ FunctionBase.prototype.preventChildBlockScope = true;
7983
+
7984
+ class ArrowFunctionExpression extends FunctionBase {
7985
+ constructor() {
7986
+ super(...arguments);
7987
+ this.objectEntity = null;
7988
+ }
7989
+ createScope(parentScope) {
7990
+ this.scope = new ReturnValueScope(parentScope, this.context);
7991
+ }
7992
+ hasEffects() {
7993
+ return false;
7994
+ }
7995
+ hasEffectsWhenCalledAtPath(path, callOptions, context) {
7996
+ if (super.hasEffectsWhenCalledAtPath(path, callOptions, context))
7997
+ return true;
7998
+ const { ignore, brokenFlow } = context;
7999
+ context.ignore = {
8000
+ breaks: false,
8001
+ continues: false,
8002
+ labels: new Set(),
8003
+ returnYield: true
8004
+ };
8005
+ if (this.body.hasEffects(context))
8006
+ return true;
8007
+ context.ignore = ignore;
8008
+ context.brokenFlow = brokenFlow;
8009
+ return false;
8010
+ }
8011
+ include(context, includeChildrenRecursively) {
8012
+ super.include(context, includeChildrenRecursively);
8013
+ for (const param of this.params) {
8014
+ if (!(param instanceof Identifier)) {
8015
+ param.include(context, includeChildrenRecursively);
8016
+ }
8017
+ }
8018
+ }
8019
+ getObjectEntity() {
8020
+ if (this.objectEntity !== null) {
8021
+ return this.objectEntity;
8022
+ }
8023
+ return (this.objectEntity = new ObjectEntity([], OBJECT_PROTOTYPE));
8024
+ }
8025
+ }
7951
8026
 
7952
8027
  function getSystemExportStatement(exportedVariables, { exportNamesByVariable, snippets: { _, getObject, getPropertyAccess } }, modifier = '') {
7953
8028
  if (exportedVariables.length === 1 &&
@@ -8241,85 +8316,26 @@ class FunctionScope extends ReturnValueScope {
8241
8316
  }
8242
8317
  }
8243
8318
 
8244
- class FunctionNode extends NodeBase {
8319
+ class FunctionNode extends FunctionBase {
8245
8320
  constructor() {
8246
8321
  super(...arguments);
8247
- this.deoptimizedReturn = false;
8248
- this.isPrototypeDeoptimized = false;
8322
+ this.objectEntity = null;
8249
8323
  }
8250
8324
  createScope(parentScope) {
8251
8325
  this.scope = new FunctionScope(parentScope, this.context);
8252
8326
  }
8253
- deoptimizePath(path) {
8254
- if (path.length === 1) {
8255
- if (path[0] === 'prototype') {
8256
- this.isPrototypeDeoptimized = true;
8257
- }
8258
- else if (path[0] === UnknownKey) {
8259
- this.isPrototypeDeoptimized = true;
8260
- // A reassignment of UNKNOWN_PATH is considered equivalent to having lost track
8261
- // which means the return expression needs to be reassigned as well
8262
- this.scope.getReturnExpression().deoptimizePath(UNKNOWN_PATH);
8263
- }
8264
- }
8265
- }
8266
- // TODO for completeness, we should also track other events here
8267
- deoptimizeThisOnEventAtPath(event, path, thisParameter) {
8268
- if (event === EVENT_CALLED) {
8269
- if (path.length > 0) {
8270
- thisParameter.deoptimizePath(UNKNOWN_PATH);
8271
- }
8272
- else {
8273
- this.scope.thisVariable.addEntityToBeDeoptimized(thisParameter);
8274
- }
8275
- }
8276
- }
8277
- getReturnExpressionWhenCalledAtPath(path) {
8278
- if (path.length !== 0) {
8279
- return UNKNOWN_EXPRESSION;
8280
- }
8281
- if (this.async) {
8282
- if (!this.deoptimizedReturn) {
8283
- this.deoptimizedReturn = true;
8284
- this.scope.getReturnExpression().deoptimizePath(UNKNOWN_PATH);
8285
- this.context.requestTreeshakingPass();
8286
- }
8287
- return UNKNOWN_EXPRESSION;
8327
+ deoptimizeThisOnEventAtPath(event, path, thisParameter, recursionTracker) {
8328
+ super.deoptimizeThisOnEventAtPath(event, path, thisParameter, recursionTracker);
8329
+ if (event === EVENT_CALLED && path.length === 0) {
8330
+ this.scope.thisVariable.addEntityToBeDeoptimized(thisParameter);
8288
8331
  }
8289
- return this.scope.getReturnExpression();
8290
8332
  }
8291
8333
  hasEffects() {
8292
8334
  return this.id !== null && this.id.hasEffects();
8293
8335
  }
8294
- hasEffectsWhenAccessedAtPath(path) {
8295
- if (path.length <= 1)
8296
- return false;
8297
- return path.length > 2 || path[0] !== 'prototype' || this.isPrototypeDeoptimized;
8298
- }
8299
- hasEffectsWhenAssignedAtPath(path) {
8300
- if (path.length <= 1) {
8301
- return false;
8302
- }
8303
- return path.length > 2 || path[0] !== 'prototype' || this.isPrototypeDeoptimized;
8304
- }
8305
8336
  hasEffectsWhenCalledAtPath(path, callOptions, context) {
8306
- if (path.length > 0)
8337
+ if (super.hasEffectsWhenCalledAtPath(path, callOptions, context))
8307
8338
  return true;
8308
- if (this.async) {
8309
- const { propertyReadSideEffects } = this.context.options
8310
- .treeshake;
8311
- const returnExpression = this.scope.getReturnExpression();
8312
- if (returnExpression.hasEffectsWhenCalledAtPath(['then'], { args: NO_ARGS, thisParam: null, withNew: false }, context) ||
8313
- (propertyReadSideEffects &&
8314
- (propertyReadSideEffects === 'always' ||
8315
- returnExpression.hasEffectsWhenAccessedAtPath(['then'], context)))) {
8316
- return true;
8317
- }
8318
- }
8319
- for (const param of this.params) {
8320
- if (param.hasEffects(context))
8321
- return true;
8322
- }
8323
8339
  const thisInit = context.replacedVariableInits.get(this.scope.thisVariable);
8324
8340
  context.replacedVariableInits.set(this.scope.thisVariable, callOptions.withNew
8325
8341
  ? new ObjectEntity(Object.create(null), OBJECT_PROTOTYPE)
@@ -8344,7 +8360,7 @@ class FunctionNode extends NodeBase {
8344
8360
  return false;
8345
8361
  }
8346
8362
  include(context, includeChildrenRecursively) {
8347
- this.included = true;
8363
+ super.include(context, includeChildrenRecursively);
8348
8364
  if (this.id)
8349
8365
  this.id.include();
8350
8366
  const hasArguments = this.scope.argumentsVariable.included;
@@ -8353,27 +8369,25 @@ class FunctionNode extends NodeBase {
8353
8369
  param.include(context, includeChildrenRecursively);
8354
8370
  }
8355
8371
  }
8356
- const { brokenFlow } = context;
8357
- context.brokenFlow = BROKEN_FLOW_NONE;
8358
- this.body.include(context, includeChildrenRecursively);
8359
- context.brokenFlow = brokenFlow;
8360
- }
8361
- includeCallArguments(context, args) {
8362
- this.scope.includeCallArguments(context, args);
8363
8372
  }
8364
8373
  initialise() {
8365
- if (this.id !== null) {
8366
- this.id.declare('function', this);
8367
- }
8368
- this.scope.addParameterVariables(this.params.map(param => param.declare('parameter', UNKNOWN_EXPRESSION)), this.params[this.params.length - 1] instanceof RestElement);
8369
- this.body.addImplicitReturnExpressionToScope();
8374
+ var _a;
8375
+ super.initialise();
8376
+ (_a = this.id) === null || _a === void 0 ? void 0 : _a.declare('function', this);
8370
8377
  }
8371
- parseNode(esTreeNode) {
8372
- this.body = new BlockStatement(esTreeNode.body, this, this.scope.hoistedBodyVarScope);
8373
- super.parseNode(esTreeNode);
8378
+ getObjectEntity() {
8379
+ if (this.objectEntity !== null) {
8380
+ return this.objectEntity;
8381
+ }
8382
+ return (this.objectEntity = new ObjectEntity([
8383
+ {
8384
+ key: 'prototype',
8385
+ kind: 'init',
8386
+ property: new ObjectEntity([], OBJECT_PROTOTYPE)
8387
+ }
8388
+ ], OBJECT_PROTOTYPE));
8374
8389
  }
8375
8390
  }
8376
- FunctionNode.prototype.preventChildBlockScope = true;
8377
8391
 
8378
8392
  class AwaitExpression extends NodeBase {
8379
8393
  constructor() {
@@ -8623,7 +8637,11 @@ class MemberExpression extends NodeBase {
8623
8637
  }
8624
8638
  else if (!this.replacement) {
8625
8639
  if (path.length < MAX_PATH_DEPTH) {
8626
- this.object.deoptimizePath([this.getPropertyKey(), ...path]);
8640
+ const propertyKey = this.getPropertyKey();
8641
+ this.object.deoptimizePath([
8642
+ propertyKey === UnknownKey ? UnknownNonAccessorKey : propertyKey,
8643
+ ...path
8644
+ ]);
8627
8645
  }
8628
8646
  }
8629
8647
  }