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
 
@@ -27,7 +27,7 @@ function _interopNamespaceDefault(e) {
27
27
  return n;
28
28
  }
29
29
 
30
- var version$1 = "2.71.1";
30
+ var version$1 = "2.73.0";
31
31
 
32
32
  function ensureArray$1(items) {
33
33
  if (Array.isArray(items)) {
@@ -2155,9 +2155,16 @@ function getOrCreate(map, key, init) {
2155
2155
  }
2156
2156
 
2157
2157
  const UnknownKey = Symbol('Unknown Key');
2158
+ const UnknownNonAccessorKey = Symbol('Unknown Non-Accessor Key');
2158
2159
  const UnknownInteger = Symbol('Unknown Integer');
2159
2160
  const EMPTY_PATH = [];
2160
2161
  const UNKNOWN_PATH = [UnknownKey];
2162
+ // For deoptimizations, this means we are modifying an unknown property but did
2163
+ // not lose track of the object or are creating a setter/getter;
2164
+ // For assignment effects it means we do not check for setter/getter effects
2165
+ // but only if something is mutated that is included, which is relevant for
2166
+ // Object.defineProperty
2167
+ const UNKNOWN_NON_ACCESSOR_PATH = [UnknownNonAccessorKey];
2161
2168
  const UNKNOWN_INTEGER_PATH = [UnknownInteger];
2162
2169
  const EntitiesKey = Symbol('Entities');
2163
2170
  class PathTracker {
@@ -4711,7 +4718,7 @@ const UNDEFINED_EXPRESSION = new (class UndefinedExpression extends ExpressionEn
4711
4718
  })();
4712
4719
  const returnsUnknown = {
4713
4720
  value: {
4714
- callsArgs: null,
4721
+ hasEffectsWhenCalled: null,
4715
4722
  returns: UNKNOWN_EXPRESSION
4716
4723
  }
4717
4724
  };
@@ -4734,7 +4741,7 @@ const UNKNOWN_LITERAL_BOOLEAN = new (class UnknownBoolean extends ExpressionEnti
4734
4741
  })();
4735
4742
  const returnsBoolean = {
4736
4743
  value: {
4737
- callsArgs: null,
4744
+ hasEffectsWhenCalled: null,
4738
4745
  returns: UNKNOWN_LITERAL_BOOLEAN
4739
4746
  }
4740
4747
  };
@@ -4757,7 +4764,7 @@ const UNKNOWN_LITERAL_NUMBER = new (class UnknownNumber extends ExpressionEntity
4757
4764
  })();
4758
4765
  const returnsNumber = {
4759
4766
  value: {
4760
- callsArgs: null,
4767
+ hasEffectsWhenCalled: null,
4761
4768
  returns: UNKNOWN_LITERAL_NUMBER
4762
4769
  }
4763
4770
  };
@@ -4780,7 +4787,24 @@ const UNKNOWN_LITERAL_STRING = new (class UnknownString extends ExpressionEntity
4780
4787
  })();
4781
4788
  const returnsString = {
4782
4789
  value: {
4783
- callsArgs: null,
4790
+ hasEffectsWhenCalled: null,
4791
+ returns: UNKNOWN_LITERAL_STRING
4792
+ }
4793
+ };
4794
+ const stringReplace = {
4795
+ value: {
4796
+ hasEffectsWhenCalled(callOptions, context) {
4797
+ const arg1 = callOptions.args[1];
4798
+ return (callOptions.args.length < 2 ||
4799
+ (arg1.getLiteralValueAtPath(EMPTY_PATH, SHARED_RECURSION_TRACKER, {
4800
+ deoptimizeCache() { }
4801
+ }) === UnknownValue &&
4802
+ arg1.hasEffectsWhenCalledAtPath(EMPTY_PATH, {
4803
+ args: NO_ARGS,
4804
+ thisParam: null,
4805
+ withNew: false
4806
+ }, context)));
4807
+ },
4784
4808
  returns: UNKNOWN_LITERAL_STRING
4785
4809
  }
4786
4810
  };
@@ -4828,18 +4852,8 @@ const literalStringMembers = assembleMemberDescriptions({
4828
4852
  padEnd: returnsString,
4829
4853
  padStart: returnsString,
4830
4854
  repeat: returnsString,
4831
- replace: {
4832
- value: {
4833
- callsArgs: [1],
4834
- returns: UNKNOWN_LITERAL_STRING
4835
- }
4836
- },
4837
- replaceAll: {
4838
- value: {
4839
- callsArgs: [1],
4840
- returns: UNKNOWN_LITERAL_STRING
4841
- }
4842
- },
4855
+ replace: stringReplace,
4856
+ replaceAll: stringReplace,
4843
4857
  search: returnsNumber,
4844
4858
  slice: returnsString,
4845
4859
  small: returnsString,
@@ -4874,21 +4888,11 @@ function getLiteralMembersForValue(value) {
4874
4888
  return Object.create(null);
4875
4889
  }
4876
4890
  function hasMemberEffectWhenCalled(members, memberName, callOptions, context) {
4891
+ var _a, _b;
4877
4892
  if (typeof memberName !== 'string' || !members[memberName]) {
4878
4893
  return true;
4879
4894
  }
4880
- if (!members[memberName].callsArgs)
4881
- return false;
4882
- for (const argIndex of members[memberName].callsArgs) {
4883
- if (callOptions.args[argIndex] &&
4884
- callOptions.args[argIndex].hasEffectsWhenCalledAtPath(EMPTY_PATH, {
4885
- args: NO_ARGS,
4886
- thisParam: null,
4887
- withNew: false
4888
- }, context))
4889
- return true;
4890
- }
4891
- return false;
4895
+ return ((_b = (_a = members[memberName]).hasEffectsWhenCalled) === null || _b === void 0 ? void 0 : _b.call(_a, callOptions, context)) || false;
4892
4896
  }
4893
4897
  function getMemberReturnExpressionWhenCalled(members, memberName) {
4894
4898
  if (typeof memberName !== 'string' || !members[memberName])
@@ -5595,6 +5599,7 @@ class ObjectEntity extends ExpressionEntity {
5595
5599
  this.deoptimizedPaths = Object.create(null);
5596
5600
  this.expressionsToBeDeoptimizedByKey = Object.create(null);
5597
5601
  this.gettersByKey = Object.create(null);
5602
+ this.hasLostTrack = false;
5598
5603
  this.hasUnknownDeoptimizedInteger = false;
5599
5604
  this.hasUnknownDeoptimizedProperty = false;
5600
5605
  this.propertiesAndGettersByKey = Object.create(null);
@@ -5615,12 +5620,18 @@ class ObjectEntity extends ExpressionEntity {
5615
5620
  }
5616
5621
  }
5617
5622
  }
5618
- deoptimizeAllProperties() {
5623
+ deoptimizeAllProperties(noAccessors) {
5619
5624
  var _a;
5620
- if (this.hasUnknownDeoptimizedProperty) {
5625
+ const isDeoptimized = this.hasLostTrack || this.hasUnknownDeoptimizedProperty;
5626
+ if (noAccessors) {
5627
+ this.hasUnknownDeoptimizedProperty = true;
5628
+ }
5629
+ else {
5630
+ this.hasLostTrack = true;
5631
+ }
5632
+ if (isDeoptimized) {
5621
5633
  return;
5622
5634
  }
5623
- this.hasUnknownDeoptimizedProperty = true;
5624
5635
  for (const properties of Object.values(this.propertiesAndGettersByKey).concat(Object.values(this.settersByKey))) {
5625
5636
  for (const property of properties) {
5626
5637
  property.deoptimizePath(UNKNOWN_PATH);
@@ -5631,7 +5642,9 @@ class ObjectEntity extends ExpressionEntity {
5631
5642
  this.deoptimizeCachedEntities();
5632
5643
  }
5633
5644
  deoptimizeIntegerProperties() {
5634
- if (this.hasUnknownDeoptimizedProperty || this.hasUnknownDeoptimizedInteger) {
5645
+ if (this.hasLostTrack ||
5646
+ this.hasUnknownDeoptimizedProperty ||
5647
+ this.hasUnknownDeoptimizedInteger) {
5635
5648
  return;
5636
5649
  }
5637
5650
  this.hasUnknownDeoptimizedInteger = true;
@@ -5644,17 +5657,19 @@ class ObjectEntity extends ExpressionEntity {
5644
5657
  }
5645
5658
  this.deoptimizeCachedIntegerEntities();
5646
5659
  }
5660
+ // Assumption: If only a specific path is deoptimized, no accessors are created
5647
5661
  deoptimizePath(path) {
5648
5662
  var _a;
5649
- if (this.hasUnknownDeoptimizedProperty || this.immutable)
5663
+ if (this.hasLostTrack || this.immutable) {
5650
5664
  return;
5665
+ }
5651
5666
  const key = path[0];
5652
5667
  if (path.length === 1) {
5653
5668
  if (typeof key !== 'string') {
5654
5669
  if (key === UnknownInteger) {
5655
5670
  return this.deoptimizeIntegerProperties();
5656
5671
  }
5657
- return this.deoptimizeAllProperties();
5672
+ return this.deoptimizeAllProperties(key === UnknownNonAccessorKey);
5658
5673
  }
5659
5674
  if (!this.deoptimizedPaths[key]) {
5660
5675
  this.deoptimizedPaths[key] = true;
@@ -5674,16 +5689,16 @@ class ObjectEntity extends ExpressionEntity {
5674
5689
  : this.allProperties) {
5675
5690
  property.deoptimizePath(subPath);
5676
5691
  }
5677
- (_a = this.prototypeExpression) === null || _a === void 0 ? void 0 : _a.deoptimizePath(path.length === 1 ? [UnknownKey, UnknownKey] : path);
5692
+ (_a = this.prototypeExpression) === null || _a === void 0 ? void 0 : _a.deoptimizePath(path.length === 1 ? [...path, UnknownKey] : path);
5678
5693
  }
5679
5694
  deoptimizeThisOnEventAtPath(event, path, thisParameter, recursionTracker) {
5680
5695
  var _a;
5681
5696
  const [key, ...subPath] = path;
5682
- if (this.hasUnknownDeoptimizedProperty ||
5697
+ if (this.hasLostTrack ||
5683
5698
  // single paths that are deoptimized will not become getters or setters
5684
5699
  ((event === EVENT_CALLED || path.length > 1) &&
5685
- typeof key === 'string' &&
5686
- this.deoptimizedPaths[key])) {
5700
+ (this.hasUnknownDeoptimizedProperty ||
5701
+ (typeof key === 'string' && this.deoptimizedPaths[key])))) {
5687
5702
  thisParameter.deoptimizePath(UNKNOWN_PATH);
5688
5703
  return;
5689
5704
  }
@@ -5781,7 +5796,7 @@ class ObjectEntity extends ExpressionEntity {
5781
5796
  }
5782
5797
  return true;
5783
5798
  }
5784
- if (this.hasUnknownDeoptimizedProperty)
5799
+ if (this.hasLostTrack)
5785
5800
  return true;
5786
5801
  if (typeof key === 'string') {
5787
5802
  if (this.propertiesAndGettersByKey[key]) {
@@ -5828,9 +5843,10 @@ class ObjectEntity extends ExpressionEntity {
5828
5843
  }
5829
5844
  return true;
5830
5845
  }
5831
- if (this.hasUnknownDeoptimizedProperty)
5846
+ if (key === UnknownNonAccessorKey)
5847
+ return false;
5848
+ if (this.hasLostTrack)
5832
5849
  return true;
5833
- // We do not need to test for unknown properties as in that case, hasUnknownDeoptimizedProperty is true
5834
5850
  if (typeof key === 'string') {
5835
5851
  if (this.propertiesAndSettersByKey[key]) {
5836
5852
  const setters = this.settersByKey[key];
@@ -5848,6 +5864,14 @@ class ObjectEntity extends ExpressionEntity {
5848
5864
  }
5849
5865
  }
5850
5866
  }
5867
+ else {
5868
+ for (const setters of Object.values(this.settersByKey).concat([this.unmatchableSetters])) {
5869
+ for (const setter of setters) {
5870
+ if (setter.hasEffectsWhenAssignedAtPath(subPath, context))
5871
+ return true;
5872
+ }
5873
+ }
5874
+ }
5851
5875
  if (this.prototypeExpression) {
5852
5876
  return this.prototypeExpression.hasEffectsWhenAssignedAtPath(path, context);
5853
5877
  }
@@ -5931,7 +5955,8 @@ class ObjectEntity extends ExpressionEntity {
5931
5955
  }
5932
5956
  }
5933
5957
  getMemberExpression(key) {
5934
- if (this.hasUnknownDeoptimizedProperty ||
5958
+ if (this.hasLostTrack ||
5959
+ this.hasUnknownDeoptimizedProperty ||
5935
5960
  typeof key !== 'string' ||
5936
5961
  (this.hasUnknownDeoptimizedInteger && INTEGER_REG_EXP.test(key)) ||
5937
5962
  this.deoptimizedPaths[key]) {
@@ -6312,7 +6337,7 @@ class LocalVariable extends Variable {
6312
6337
  if (this.isReassigned)
6313
6338
  return true;
6314
6339
  return (this.init &&
6315
- !context.accessed.trackEntityAtPathAndGetIfTracked(path, this) &&
6340
+ !context.assigned.trackEntityAtPathAndGetIfTracked(path, this) &&
6316
6341
  this.init.hasEffectsWhenAssignedAtPath(path, context));
6317
6342
  }
6318
6343
  hasEffectsWhenCalledAtPath(path, callOptions, context) {
@@ -6597,323 +6622,89 @@ class ReturnValueScope extends ParameterScope {
6597
6622
  }
6598
6623
  }
6599
6624
 
6600
- function treeshakeNode(node, code, start, end) {
6601
- code.remove(start, end);
6602
- if (node.annotations) {
6603
- for (const annotation of node.annotations) {
6604
- if (annotation.start < start) {
6605
- code.remove(annotation.start, annotation.end);
6606
- }
6607
- else {
6608
- return;
6609
- }
6610
- }
6611
- }
6612
- }
6613
- function removeAnnotations(node, code) {
6614
- if (!node.annotations && node.parent.type === ExpressionStatement$1) {
6615
- node = node.parent;
6616
- }
6617
- if (node.annotations) {
6618
- for (const annotation of node.annotations) {
6619
- code.remove(annotation.start, annotation.end);
6620
- }
6621
- }
6622
- }
6625
+ //@ts-check
6626
+ /** @typedef { import('estree').Node} Node */
6627
+ /** @typedef {Node | {
6628
+ * type: 'PropertyDefinition';
6629
+ * computed: boolean;
6630
+ * value: Node
6631
+ * }} NodeWithPropertyDefinition */
6623
6632
 
6624
- const NO_SEMICOLON = { isNoStatement: true };
6625
- // This assumes there are only white-space and comments between start and the string we are looking for
6626
- function findFirstOccurrenceOutsideComment(code, searchString, start = 0) {
6627
- let searchPos, charCodeAfterSlash;
6628
- searchPos = code.indexOf(searchString, start);
6629
- while (true) {
6630
- start = code.indexOf('/', start);
6631
- if (start === -1 || start >= searchPos)
6632
- return searchPos;
6633
- charCodeAfterSlash = code.charCodeAt(++start);
6634
- ++start;
6635
- // With our assumption, '/' always starts a comment. Determine comment type:
6636
- start =
6637
- charCodeAfterSlash === 47 /*"/"*/
6638
- ? code.indexOf('\n', start) + 1
6639
- : code.indexOf('*/', start) + 2;
6640
- if (start > searchPos) {
6641
- searchPos = code.indexOf(searchString, start);
6642
- }
6643
- }
6644
- }
6645
- const NON_WHITESPACE = /\S/g;
6646
- function findNonWhiteSpace(code, index) {
6647
- NON_WHITESPACE.lastIndex = index;
6648
- const result = NON_WHITESPACE.exec(code);
6649
- return result.index;
6650
- }
6651
- // This assumes "code" only contains white-space and comments
6652
- // Returns position of line-comment if applicable
6653
- function findFirstLineBreakOutsideComment(code) {
6654
- let lineBreakPos, charCodeAfterSlash, start = 0;
6655
- lineBreakPos = code.indexOf('\n', start);
6656
- while (true) {
6657
- start = code.indexOf('/', start);
6658
- if (start === -1 || start > lineBreakPos)
6659
- return [lineBreakPos, lineBreakPos + 1];
6660
- // With our assumption, '/' always starts a comment. Determine comment type:
6661
- charCodeAfterSlash = code.charCodeAt(start + 1);
6662
- if (charCodeAfterSlash === 47 /*"/"*/)
6663
- return [start, lineBreakPos + 1];
6664
- start = code.indexOf('*/', start + 3) + 2;
6665
- if (start > lineBreakPos) {
6666
- lineBreakPos = code.indexOf('\n', start);
6667
- }
6668
- }
6633
+ /**
6634
+ *
6635
+ * @param {NodeWithPropertyDefinition} node
6636
+ * @param {NodeWithPropertyDefinition} parent
6637
+ * @returns boolean
6638
+ */
6639
+ function is_reference (node, parent) {
6640
+ if (node.type === 'MemberExpression') {
6641
+ return !node.computed && is_reference(node.object, node);
6642
+ }
6643
+
6644
+ if (node.type === 'Identifier') {
6645
+ if (!parent) return true;
6646
+
6647
+ switch (parent.type) {
6648
+ // disregard `bar` in `foo.bar`
6649
+ case 'MemberExpression': return parent.computed || node === parent.object;
6650
+
6651
+ // disregard the `foo` in `class {foo(){}}` but keep it in `class {[foo](){}}`
6652
+ case 'MethodDefinition': return parent.computed;
6653
+
6654
+ // disregard the `foo` in `class {foo=bar}` but keep it in `class {[foo]=bar}` and `class {bar=foo}`
6655
+ case 'PropertyDefinition': return parent.computed || node === parent.value;
6656
+
6657
+ // disregard the `bar` in `{ bar: foo }`, but keep it in `{ [bar]: foo }`
6658
+ case 'Property': return parent.computed || node === parent.value;
6659
+
6660
+ // disregard the `bar` in `export { foo as bar }` or
6661
+ // the foo in `import { foo as bar }`
6662
+ case 'ExportSpecifier':
6663
+ case 'ImportSpecifier': return node === parent.local;
6664
+
6665
+ // disregard the `foo` in `foo: while (...) { ... break foo; ... continue foo;}`
6666
+ case 'LabeledStatement':
6667
+ case 'BreakStatement':
6668
+ case 'ContinueStatement': return false;
6669
+ default: return true;
6670
+ }
6671
+ }
6672
+
6673
+ return false;
6669
6674
  }
6670
- function renderStatementList(statements, code, start, end, options) {
6671
- let currentNode, currentNodeStart, currentNodeNeedsBoundaries, nextNodeStart;
6672
- let nextNode = statements[0];
6673
- let nextNodeNeedsBoundaries = !nextNode.included || nextNode.needsBoundaries;
6674
- if (nextNodeNeedsBoundaries) {
6675
- nextNodeStart =
6676
- start + findFirstLineBreakOutsideComment(code.original.slice(start, nextNode.start))[1];
6677
- }
6678
- for (let nextIndex = 1; nextIndex <= statements.length; nextIndex++) {
6679
- currentNode = nextNode;
6680
- currentNodeStart = nextNodeStart;
6681
- currentNodeNeedsBoundaries = nextNodeNeedsBoundaries;
6682
- nextNode = statements[nextIndex];
6683
- nextNodeNeedsBoundaries =
6684
- nextNode === undefined ? false : !nextNode.included || nextNode.needsBoundaries;
6685
- if (currentNodeNeedsBoundaries || nextNodeNeedsBoundaries) {
6686
- nextNodeStart =
6687
- currentNode.end +
6688
- findFirstLineBreakOutsideComment(code.original.slice(currentNode.end, nextNode === undefined ? end : nextNode.start))[1];
6689
- if (currentNode.included) {
6690
- currentNodeNeedsBoundaries
6691
- ? currentNode.render(code, options, {
6692
- end: nextNodeStart,
6693
- start: currentNodeStart
6694
- })
6695
- : currentNode.render(code, options);
6696
- }
6697
- else {
6698
- treeshakeNode(currentNode, code, currentNodeStart, nextNodeStart);
6699
- }
6700
- }
6701
- else {
6702
- currentNode.render(code, options);
6703
- }
6675
+
6676
+ /* eslint sort-keys: "off" */
6677
+ const ValueProperties = Symbol('Value Properties');
6678
+ const PURE = {
6679
+ hasEffectsWhenCalled() {
6680
+ return false;
6704
6681
  }
6705
- }
6706
- // This assumes that the first character is not part of the first node
6707
- function getCommaSeparatedNodesWithBoundaries(nodes, code, start, end) {
6708
- const splitUpNodes = [];
6709
- let node, nextNode, nextNodeStart, contentEnd, char;
6710
- let separator = start - 1;
6711
- for (let nextIndex = 0; nextIndex < nodes.length; nextIndex++) {
6712
- nextNode = nodes[nextIndex];
6713
- if (node !== undefined) {
6714
- separator =
6715
- node.end +
6716
- findFirstOccurrenceOutsideComment(code.original.slice(node.end, nextNode.start), ',');
6717
- }
6718
- nextNodeStart = contentEnd =
6719
- separator +
6720
- 1 +
6721
- findFirstLineBreakOutsideComment(code.original.slice(separator + 1, nextNode.start))[1];
6722
- while (((char = code.original.charCodeAt(nextNodeStart)),
6723
- char === 32 /*" "*/ || char === 9 /*"\t"*/ || char === 10 /*"\n"*/ || char === 13) /*"\r"*/)
6724
- nextNodeStart++;
6725
- if (node !== undefined) {
6726
- splitUpNodes.push({
6727
- contentEnd,
6728
- end: nextNodeStart,
6729
- node,
6730
- separator,
6731
- start
6732
- });
6733
- }
6734
- node = nextNode;
6735
- start = nextNodeStart;
6682
+ };
6683
+ const IMPURE = {
6684
+ hasEffectsWhenCalled() {
6685
+ return true;
6736
6686
  }
6737
- splitUpNodes.push({
6738
- contentEnd: end,
6739
- end,
6740
- node: node,
6741
- separator: null,
6742
- start
6743
- });
6744
- return splitUpNodes;
6745
- }
6746
- // This assumes there are only white-space and comments between start and end
6747
- function removeLineBreaks(code, start, end) {
6748
- while (true) {
6749
- const [removeStart, removeEnd] = findFirstLineBreakOutsideComment(code.original.slice(start, end));
6750
- if (removeStart === -1) {
6751
- break;
6687
+ };
6688
+ // We use shortened variables to reduce file size here
6689
+ /* OBJECT */
6690
+ const O = {
6691
+ __proto__: null,
6692
+ [ValueProperties]: IMPURE
6693
+ };
6694
+ /* PURE FUNCTION */
6695
+ const PF = {
6696
+ __proto__: null,
6697
+ [ValueProperties]: PURE
6698
+ };
6699
+ /* FUNCTION THAT MUTATES FIRST ARG WITHOUT TRIGGERING ACCESSORS */
6700
+ const MUTATES_ARG_WITHOUT_ACCESSOR = {
6701
+ __proto__: null,
6702
+ [ValueProperties]: {
6703
+ hasEffectsWhenCalled(callOptions, context) {
6704
+ return (!callOptions.args.length ||
6705
+ callOptions.args[0].hasEffectsWhenAssignedAtPath(UNKNOWN_NON_ACCESSOR_PATH, context));
6752
6706
  }
6753
- code.remove(start + removeStart, (start += removeEnd));
6754
6707
  }
6755
- }
6756
-
6757
- class BlockScope extends ChildScope {
6758
- addDeclaration(identifier, context, init, isHoisted) {
6759
- if (isHoisted) {
6760
- const variable = this.parent.addDeclaration(identifier, context, init, isHoisted);
6761
- // Necessary to make sure the init is deoptimized for conditional declarations.
6762
- // We cannot call deoptimizePath here.
6763
- variable.markInitializersForDeoptimization();
6764
- return variable;
6765
- }
6766
- else {
6767
- return super.addDeclaration(identifier, context, init, false);
6768
- }
6769
- }
6770
- }
6771
-
6772
- class ExpressionStatement extends NodeBase {
6773
- initialise() {
6774
- if (this.directive &&
6775
- this.directive !== 'use strict' &&
6776
- this.parent.type === Program$1) {
6777
- this.context.warn(
6778
- // This is necessary, because either way (deleting or not) can lead to errors.
6779
- {
6780
- code: 'MODULE_LEVEL_DIRECTIVE',
6781
- message: `Module level directives cause errors when bundled, '${this.directive}' was ignored.`
6782
- }, this.start);
6783
- }
6784
- }
6785
- render(code, options) {
6786
- super.render(code, options);
6787
- if (this.included)
6788
- this.insertSemicolon(code);
6789
- }
6790
- shouldBeIncluded(context) {
6791
- if (this.directive && this.directive !== 'use strict')
6792
- return this.parent.type !== Program$1;
6793
- return super.shouldBeIncluded(context);
6794
- }
6795
- }
6796
-
6797
- class BlockStatement extends NodeBase {
6798
- constructor() {
6799
- super(...arguments);
6800
- this.directlyIncluded = false;
6801
- }
6802
- addImplicitReturnExpressionToScope() {
6803
- const lastStatement = this.body[this.body.length - 1];
6804
- if (!lastStatement || lastStatement.type !== ReturnStatement$1) {
6805
- this.scope.addReturnExpression(UNKNOWN_EXPRESSION);
6806
- }
6807
- }
6808
- createScope(parentScope) {
6809
- this.scope = this.parent.preventChildBlockScope
6810
- ? parentScope
6811
- : new BlockScope(parentScope);
6812
- }
6813
- hasEffects(context) {
6814
- if (this.deoptimizeBody)
6815
- return true;
6816
- for (const node of this.body) {
6817
- if (context.brokenFlow)
6818
- break;
6819
- if (node.hasEffects(context))
6820
- return true;
6821
- }
6822
- return false;
6823
- }
6824
- include(context, includeChildrenRecursively) {
6825
- if (!(this.deoptimizeBody && this.directlyIncluded)) {
6826
- this.included = true;
6827
- this.directlyIncluded = true;
6828
- if (this.deoptimizeBody)
6829
- includeChildrenRecursively = true;
6830
- for (const node of this.body) {
6831
- if (includeChildrenRecursively || node.shouldBeIncluded(context))
6832
- node.include(context, includeChildrenRecursively);
6833
- }
6834
- }
6835
- }
6836
- initialise() {
6837
- const firstBodyStatement = this.body[0];
6838
- this.deoptimizeBody =
6839
- firstBodyStatement instanceof ExpressionStatement &&
6840
- firstBodyStatement.directive === 'use asm';
6841
- }
6842
- render(code, options) {
6843
- if (this.body.length) {
6844
- renderStatementList(this.body, code, this.start + 1, this.end - 1, options);
6845
- }
6846
- else {
6847
- super.render(code, options);
6848
- }
6849
- }
6850
- }
6851
-
6852
- //@ts-check
6853
- /** @typedef { import('estree').Node} Node */
6854
- /** @typedef {Node | {
6855
- * type: 'PropertyDefinition';
6856
- * computed: boolean;
6857
- * value: Node
6858
- * }} NodeWithPropertyDefinition */
6859
-
6860
- /**
6861
- *
6862
- * @param {NodeWithPropertyDefinition} node
6863
- * @param {NodeWithPropertyDefinition} parent
6864
- * @returns boolean
6865
- */
6866
- function is_reference (node, parent) {
6867
- if (node.type === 'MemberExpression') {
6868
- return !node.computed && is_reference(node.object, node);
6869
- }
6870
-
6871
- if (node.type === 'Identifier') {
6872
- if (!parent) return true;
6873
-
6874
- switch (parent.type) {
6875
- // disregard `bar` in `foo.bar`
6876
- case 'MemberExpression': return parent.computed || node === parent.object;
6877
-
6878
- // disregard the `foo` in `class {foo(){}}` but keep it in `class {[foo](){}}`
6879
- case 'MethodDefinition': return parent.computed;
6880
-
6881
- // disregard the `foo` in `class {foo=bar}` but keep it in `class {[foo]=bar}` and `class {bar=foo}`
6882
- case 'PropertyDefinition': return parent.computed || node === parent.value;
6883
-
6884
- // disregard the `bar` in `{ bar: foo }`, but keep it in `{ [bar]: foo }`
6885
- case 'Property': return parent.computed || node === parent.value;
6886
-
6887
- // disregard the `bar` in `export { foo as bar }` or
6888
- // the foo in `import { foo as bar }`
6889
- case 'ExportSpecifier':
6890
- case 'ImportSpecifier': return node === parent.local;
6891
-
6892
- // disregard the `foo` in `foo: while (...) { ... break foo; ... continue foo;}`
6893
- case 'LabeledStatement':
6894
- case 'BreakStatement':
6895
- case 'ContinueStatement': return false;
6896
- default: return true;
6897
- }
6898
- }
6899
-
6900
- return false;
6901
- }
6902
-
6903
- /* eslint sort-keys: "off" */
6904
- const ValueProperties = Symbol('Value Properties');
6905
- const PURE = { pure: true };
6906
- const IMPURE = { pure: false };
6907
- // We use shortened variables to reduce file size here
6908
- /* OBJECT */
6909
- const O = {
6910
- __proto__: null,
6911
- [ValueProperties]: IMPURE
6912
- };
6913
- /* PURE FUNCTION */
6914
- const PF = {
6915
- __proto__: null,
6916
- [ValueProperties]: PURE
6917
6708
  };
6918
6709
  /* CONSTRUCTOR */
6919
6710
  const C = {
@@ -7053,6 +6844,11 @@ const knownGlobals = {
7053
6844
  __proto__: null,
7054
6845
  [ValueProperties]: PURE,
7055
6846
  create: PF,
6847
+ // Technically those can throw in certain situations, but we ignore this as
6848
+ // code that relies on this will hopefully wrap this in a try-catch, which
6849
+ // deoptimizes everything anyway
6850
+ defineProperty: MUTATES_ARG_WITHOUT_ACCESSOR,
6851
+ defineProperties: MUTATES_ARG_WITHOUT_ACCESSOR,
7056
6852
  getOwnPropertyDescriptor: PF,
7057
6853
  getOwnPropertyNames: PF,
7058
6854
  getOwnPropertySymbols: PF,
@@ -7736,27 +7532,24 @@ function getGlobalAtPath(path) {
7736
7532
  }
7737
7533
  return currentGlobal[ValueProperties];
7738
7534
  }
7739
- function isPureGlobal(path) {
7740
- const globalAtPath = getGlobalAtPath(path);
7741
- return globalAtPath !== null && globalAtPath.pure;
7742
- }
7743
- function isGlobalMember(path) {
7744
- if (path.length === 1) {
7745
- return path[0] === 'undefined' || getGlobalAtPath(path) !== null;
7746
- }
7747
- return getGlobalAtPath(path.slice(0, -1)) !== null;
7748
- }
7749
7535
 
7750
7536
  class GlobalVariable extends Variable {
7751
7537
  constructor() {
7752
7538
  super(...arguments);
7539
+ // Ensure we use live-bindings for globals as we do not know if they have
7540
+ // been reassigned
7753
7541
  this.isReassigned = true;
7754
7542
  }
7755
7543
  hasEffectsWhenAccessedAtPath(path) {
7756
- return !isGlobalMember([this.name, ...path]);
7544
+ if (path.length === 0) {
7545
+ // Technically, "undefined" is a global variable of sorts
7546
+ return this.name !== 'undefined' && getGlobalAtPath([this.name]) === null;
7547
+ }
7548
+ return getGlobalAtPath([this.name, ...path].slice(0, -1)) === null;
7757
7549
  }
7758
- hasEffectsWhenCalledAtPath(path) {
7759
- return !isPureGlobal([this.name, ...path]);
7550
+ hasEffectsWhenCalledAtPath(path, callOptions, context) {
7551
+ const globalAtPath = getGlobalAtPath([this.name, ...path]);
7552
+ return globalAtPath === null || globalAtPath.hasEffectsWhenCalled(callOptions, context);
7760
7553
  }
7761
7554
  }
7762
7555
 
@@ -7945,60 +7738,317 @@ function closestParentFunctionOrProgram(node) {
7945
7738
  return node;
7946
7739
  }
7947
7740
 
7948
- class RestElement extends NodeBase {
7949
- constructor() {
7950
- super(...arguments);
7951
- this.deoptimized = false;
7952
- this.declarationInit = null;
7953
- }
7954
- addExportedVariables(variables, exportNamesByVariable) {
7955
- this.argument.addExportedVariables(variables, exportNamesByVariable);
7956
- }
7957
- declare(kind, init) {
7958
- this.declarationInit = init;
7959
- return this.argument.declare(kind, UNKNOWN_EXPRESSION);
7960
- }
7961
- deoptimizePath(path) {
7962
- path.length === 0 && this.argument.deoptimizePath(EMPTY_PATH);
7963
- }
7964
- hasEffectsWhenAssignedAtPath(path, context) {
7965
- return path.length > 0 || this.argument.hasEffectsWhenAssignedAtPath(EMPTY_PATH, context);
7741
+ function treeshakeNode(node, code, start, end) {
7742
+ code.remove(start, end);
7743
+ if (node.annotations) {
7744
+ for (const annotation of node.annotations) {
7745
+ if (annotation.start < start) {
7746
+ code.remove(annotation.start, annotation.end);
7747
+ }
7748
+ else {
7749
+ return;
7750
+ }
7751
+ }
7966
7752
  }
7967
- markDeclarationReached() {
7968
- this.argument.markDeclarationReached();
7753
+ }
7754
+ function removeAnnotations(node, code) {
7755
+ if (!node.annotations && node.parent.type === ExpressionStatement$1) {
7756
+ node = node.parent;
7969
7757
  }
7970
- applyDeoptimizations() {
7971
- this.deoptimized = true;
7972
- if (this.declarationInit !== null) {
7973
- this.declarationInit.deoptimizePath([UnknownKey, UnknownKey]);
7974
- this.context.requestTreeshakingPass();
7758
+ if (node.annotations) {
7759
+ for (const annotation of node.annotations) {
7760
+ code.remove(annotation.start, annotation.end);
7975
7761
  }
7976
7762
  }
7977
7763
  }
7978
7764
 
7979
- class ArrowFunctionExpression extends NodeBase {
7980
- constructor() {
7981
- super(...arguments);
7982
- this.deoptimizedReturn = false;
7983
- }
7984
- createScope(parentScope) {
7985
- this.scope = new ReturnValueScope(parentScope, this.context);
7986
- }
7987
- deoptimizePath(path) {
7988
- // A reassignment of UNKNOWN_PATH is considered equivalent to having lost track
7989
- // which means the return expression needs to be reassigned
7990
- if (path.length === 1 && path[0] === UnknownKey) {
7991
- this.scope.getReturnExpression().deoptimizePath(UNKNOWN_PATH);
7765
+ const NO_SEMICOLON = { isNoStatement: true };
7766
+ // This assumes there are only white-space and comments between start and the string we are looking for
7767
+ function findFirstOccurrenceOutsideComment(code, searchString, start = 0) {
7768
+ let searchPos, charCodeAfterSlash;
7769
+ searchPos = code.indexOf(searchString, start);
7770
+ while (true) {
7771
+ start = code.indexOf('/', start);
7772
+ if (start === -1 || start >= searchPos)
7773
+ return searchPos;
7774
+ charCodeAfterSlash = code.charCodeAt(++start);
7775
+ ++start;
7776
+ // With our assumption, '/' always starts a comment. Determine comment type:
7777
+ start =
7778
+ charCodeAfterSlash === 47 /*"/"*/
7779
+ ? code.indexOf('\n', start) + 1
7780
+ : code.indexOf('*/', start) + 2;
7781
+ if (start > searchPos) {
7782
+ searchPos = code.indexOf(searchString, start);
7992
7783
  }
7993
7784
  }
7994
- // Arrow functions do not mutate their context
7995
- deoptimizeThisOnEventAtPath() { }
7996
- getReturnExpressionWhenCalledAtPath(path) {
7997
- if (path.length !== 0) {
7998
- return UNKNOWN_EXPRESSION;
7785
+ }
7786
+ const NON_WHITESPACE = /\S/g;
7787
+ function findNonWhiteSpace(code, index) {
7788
+ NON_WHITESPACE.lastIndex = index;
7789
+ const result = NON_WHITESPACE.exec(code);
7790
+ return result.index;
7791
+ }
7792
+ // This assumes "code" only contains white-space and comments
7793
+ // Returns position of line-comment if applicable
7794
+ function findFirstLineBreakOutsideComment(code) {
7795
+ let lineBreakPos, charCodeAfterSlash, start = 0;
7796
+ lineBreakPos = code.indexOf('\n', start);
7797
+ while (true) {
7798
+ start = code.indexOf('/', start);
7799
+ if (start === -1 || start > lineBreakPos)
7800
+ return [lineBreakPos, lineBreakPos + 1];
7801
+ // With our assumption, '/' always starts a comment. Determine comment type:
7802
+ charCodeAfterSlash = code.charCodeAt(start + 1);
7803
+ if (charCodeAfterSlash === 47 /*"/"*/)
7804
+ return [start, lineBreakPos + 1];
7805
+ start = code.indexOf('*/', start + 3) + 2;
7806
+ if (start > lineBreakPos) {
7807
+ lineBreakPos = code.indexOf('\n', start);
7999
7808
  }
8000
- if (this.async) {
8001
- if (!this.deoptimizedReturn) {
7809
+ }
7810
+ }
7811
+ function renderStatementList(statements, code, start, end, options) {
7812
+ let currentNode, currentNodeStart, currentNodeNeedsBoundaries, nextNodeStart;
7813
+ let nextNode = statements[0];
7814
+ let nextNodeNeedsBoundaries = !nextNode.included || nextNode.needsBoundaries;
7815
+ if (nextNodeNeedsBoundaries) {
7816
+ nextNodeStart =
7817
+ start + findFirstLineBreakOutsideComment(code.original.slice(start, nextNode.start))[1];
7818
+ }
7819
+ for (let nextIndex = 1; nextIndex <= statements.length; nextIndex++) {
7820
+ currentNode = nextNode;
7821
+ currentNodeStart = nextNodeStart;
7822
+ currentNodeNeedsBoundaries = nextNodeNeedsBoundaries;
7823
+ nextNode = statements[nextIndex];
7824
+ nextNodeNeedsBoundaries =
7825
+ nextNode === undefined ? false : !nextNode.included || nextNode.needsBoundaries;
7826
+ if (currentNodeNeedsBoundaries || nextNodeNeedsBoundaries) {
7827
+ nextNodeStart =
7828
+ currentNode.end +
7829
+ findFirstLineBreakOutsideComment(code.original.slice(currentNode.end, nextNode === undefined ? end : nextNode.start))[1];
7830
+ if (currentNode.included) {
7831
+ currentNodeNeedsBoundaries
7832
+ ? currentNode.render(code, options, {
7833
+ end: nextNodeStart,
7834
+ start: currentNodeStart
7835
+ })
7836
+ : currentNode.render(code, options);
7837
+ }
7838
+ else {
7839
+ treeshakeNode(currentNode, code, currentNodeStart, nextNodeStart);
7840
+ }
7841
+ }
7842
+ else {
7843
+ currentNode.render(code, options);
7844
+ }
7845
+ }
7846
+ }
7847
+ // This assumes that the first character is not part of the first node
7848
+ function getCommaSeparatedNodesWithBoundaries(nodes, code, start, end) {
7849
+ const splitUpNodes = [];
7850
+ let node, nextNode, nextNodeStart, contentEnd, char;
7851
+ let separator = start - 1;
7852
+ for (let nextIndex = 0; nextIndex < nodes.length; nextIndex++) {
7853
+ nextNode = nodes[nextIndex];
7854
+ if (node !== undefined) {
7855
+ separator =
7856
+ node.end +
7857
+ findFirstOccurrenceOutsideComment(code.original.slice(node.end, nextNode.start), ',');
7858
+ }
7859
+ nextNodeStart = contentEnd =
7860
+ separator +
7861
+ 1 +
7862
+ findFirstLineBreakOutsideComment(code.original.slice(separator + 1, nextNode.start))[1];
7863
+ while (((char = code.original.charCodeAt(nextNodeStart)),
7864
+ char === 32 /*" "*/ || char === 9 /*"\t"*/ || char === 10 /*"\n"*/ || char === 13) /*"\r"*/)
7865
+ nextNodeStart++;
7866
+ if (node !== undefined) {
7867
+ splitUpNodes.push({
7868
+ contentEnd,
7869
+ end: nextNodeStart,
7870
+ node,
7871
+ separator,
7872
+ start
7873
+ });
7874
+ }
7875
+ node = nextNode;
7876
+ start = nextNodeStart;
7877
+ }
7878
+ splitUpNodes.push({
7879
+ contentEnd: end,
7880
+ end,
7881
+ node: node,
7882
+ separator: null,
7883
+ start
7884
+ });
7885
+ return splitUpNodes;
7886
+ }
7887
+ // This assumes there are only white-space and comments between start and end
7888
+ function removeLineBreaks(code, start, end) {
7889
+ while (true) {
7890
+ const [removeStart, removeEnd] = findFirstLineBreakOutsideComment(code.original.slice(start, end));
7891
+ if (removeStart === -1) {
7892
+ break;
7893
+ }
7894
+ code.remove(start + removeStart, (start += removeEnd));
7895
+ }
7896
+ }
7897
+
7898
+ class BlockScope extends ChildScope {
7899
+ addDeclaration(identifier, context, init, isHoisted) {
7900
+ if (isHoisted) {
7901
+ const variable = this.parent.addDeclaration(identifier, context, init, isHoisted);
7902
+ // Necessary to make sure the init is deoptimized for conditional declarations.
7903
+ // We cannot call deoptimizePath here.
7904
+ variable.markInitializersForDeoptimization();
7905
+ return variable;
7906
+ }
7907
+ else {
7908
+ return super.addDeclaration(identifier, context, init, false);
7909
+ }
7910
+ }
7911
+ }
7912
+
7913
+ class ExpressionStatement extends NodeBase {
7914
+ initialise() {
7915
+ if (this.directive &&
7916
+ this.directive !== 'use strict' &&
7917
+ this.parent.type === Program$1) {
7918
+ this.context.warn(
7919
+ // This is necessary, because either way (deleting or not) can lead to errors.
7920
+ {
7921
+ code: 'MODULE_LEVEL_DIRECTIVE',
7922
+ message: `Module level directives cause errors when bundled, '${this.directive}' was ignored.`
7923
+ }, this.start);
7924
+ }
7925
+ }
7926
+ render(code, options) {
7927
+ super.render(code, options);
7928
+ if (this.included)
7929
+ this.insertSemicolon(code);
7930
+ }
7931
+ shouldBeIncluded(context) {
7932
+ if (this.directive && this.directive !== 'use strict')
7933
+ return this.parent.type !== Program$1;
7934
+ return super.shouldBeIncluded(context);
7935
+ }
7936
+ }
7937
+
7938
+ class BlockStatement extends NodeBase {
7939
+ constructor() {
7940
+ super(...arguments);
7941
+ this.directlyIncluded = false;
7942
+ }
7943
+ addImplicitReturnExpressionToScope() {
7944
+ const lastStatement = this.body[this.body.length - 1];
7945
+ if (!lastStatement || lastStatement.type !== ReturnStatement$1) {
7946
+ this.scope.addReturnExpression(UNKNOWN_EXPRESSION);
7947
+ }
7948
+ }
7949
+ createScope(parentScope) {
7950
+ this.scope = this.parent.preventChildBlockScope
7951
+ ? parentScope
7952
+ : new BlockScope(parentScope);
7953
+ }
7954
+ hasEffects(context) {
7955
+ if (this.deoptimizeBody)
7956
+ return true;
7957
+ for (const node of this.body) {
7958
+ if (context.brokenFlow)
7959
+ break;
7960
+ if (node.hasEffects(context))
7961
+ return true;
7962
+ }
7963
+ return false;
7964
+ }
7965
+ include(context, includeChildrenRecursively) {
7966
+ if (!(this.deoptimizeBody && this.directlyIncluded)) {
7967
+ this.included = true;
7968
+ this.directlyIncluded = true;
7969
+ if (this.deoptimizeBody)
7970
+ includeChildrenRecursively = true;
7971
+ for (const node of this.body) {
7972
+ if (includeChildrenRecursively || node.shouldBeIncluded(context))
7973
+ node.include(context, includeChildrenRecursively);
7974
+ }
7975
+ }
7976
+ }
7977
+ initialise() {
7978
+ const firstBodyStatement = this.body[0];
7979
+ this.deoptimizeBody =
7980
+ firstBodyStatement instanceof ExpressionStatement &&
7981
+ firstBodyStatement.directive === 'use asm';
7982
+ }
7983
+ render(code, options) {
7984
+ if (this.body.length) {
7985
+ renderStatementList(this.body, code, this.start + 1, this.end - 1, options);
7986
+ }
7987
+ else {
7988
+ super.render(code, options);
7989
+ }
7990
+ }
7991
+ }
7992
+
7993
+ class RestElement extends NodeBase {
7994
+ constructor() {
7995
+ super(...arguments);
7996
+ this.deoptimized = false;
7997
+ this.declarationInit = null;
7998
+ }
7999
+ addExportedVariables(variables, exportNamesByVariable) {
8000
+ this.argument.addExportedVariables(variables, exportNamesByVariable);
8001
+ }
8002
+ declare(kind, init) {
8003
+ this.declarationInit = init;
8004
+ return this.argument.declare(kind, UNKNOWN_EXPRESSION);
8005
+ }
8006
+ deoptimizePath(path) {
8007
+ path.length === 0 && this.argument.deoptimizePath(EMPTY_PATH);
8008
+ }
8009
+ hasEffectsWhenAssignedAtPath(path, context) {
8010
+ return path.length > 0 || this.argument.hasEffectsWhenAssignedAtPath(EMPTY_PATH, context);
8011
+ }
8012
+ markDeclarationReached() {
8013
+ this.argument.markDeclarationReached();
8014
+ }
8015
+ applyDeoptimizations() {
8016
+ this.deoptimized = true;
8017
+ if (this.declarationInit !== null) {
8018
+ this.declarationInit.deoptimizePath([UnknownKey, UnknownKey]);
8019
+ this.context.requestTreeshakingPass();
8020
+ }
8021
+ }
8022
+ }
8023
+
8024
+ class FunctionBase extends NodeBase {
8025
+ constructor() {
8026
+ super(...arguments);
8027
+ this.objectEntity = null;
8028
+ this.deoptimizedReturn = false;
8029
+ }
8030
+ deoptimizePath(path) {
8031
+ this.getObjectEntity().deoptimizePath(path);
8032
+ if (path.length === 1 && path[0] === UnknownKey) {
8033
+ // A reassignment of UNKNOWN_PATH is considered equivalent to having lost track
8034
+ // which means the return expression needs to be reassigned
8035
+ this.scope.getReturnExpression().deoptimizePath(UNKNOWN_PATH);
8036
+ }
8037
+ }
8038
+ deoptimizeThisOnEventAtPath(event, path, thisParameter, recursionTracker) {
8039
+ if (path.length > 0) {
8040
+ this.getObjectEntity().deoptimizeThisOnEventAtPath(event, path, thisParameter, recursionTracker);
8041
+ }
8042
+ }
8043
+ getLiteralValueAtPath(path, recursionTracker, origin) {
8044
+ return this.getObjectEntity().getLiteralValueAtPath(path, recursionTracker, origin);
8045
+ }
8046
+ getReturnExpressionWhenCalledAtPath(path, callOptions, recursionTracker, origin) {
8047
+ if (path.length > 0) {
8048
+ return this.getObjectEntity().getReturnExpressionWhenCalledAtPath(path, callOptions, recursionTracker, origin);
8049
+ }
8050
+ if (this.async) {
8051
+ if (!this.deoptimizedReturn) {
8002
8052
  this.deoptimizedReturn = true;
8003
8053
  this.scope.getReturnExpression().deoptimizePath(UNKNOWN_PATH);
8004
8054
  this.context.requestTreeshakingPass();
@@ -8007,18 +8057,16 @@ class ArrowFunctionExpression extends NodeBase {
8007
8057
  }
8008
8058
  return this.scope.getReturnExpression();
8009
8059
  }
8010
- hasEffects() {
8011
- return false;
8012
- }
8013
- hasEffectsWhenAccessedAtPath(path) {
8014
- return path.length > 1;
8060
+ hasEffectsWhenAccessedAtPath(path, context) {
8061
+ return this.getObjectEntity().hasEffectsWhenAccessedAtPath(path, context);
8015
8062
  }
8016
- hasEffectsWhenAssignedAtPath(path) {
8017
- return path.length > 1;
8063
+ hasEffectsWhenAssignedAtPath(path, context) {
8064
+ return this.getObjectEntity().hasEffectsWhenAssignedAtPath(path, context);
8018
8065
  }
8019
- hasEffectsWhenCalledAtPath(path, _callOptions, context) {
8020
- if (path.length > 0)
8021
- return true;
8066
+ hasEffectsWhenCalledAtPath(path, callOptions, context) {
8067
+ if (path.length > 0) {
8068
+ return this.getObjectEntity().hasEffectsWhenCalledAtPath(path, callOptions, context);
8069
+ }
8022
8070
  if (this.async) {
8023
8071
  const { propertyReadSideEffects } = this.context.options
8024
8072
  .treeshake;
@@ -8034,26 +8082,10 @@ class ArrowFunctionExpression extends NodeBase {
8034
8082
  if (param.hasEffects(context))
8035
8083
  return true;
8036
8084
  }
8037
- const { ignore, brokenFlow } = context;
8038
- context.ignore = {
8039
- breaks: false,
8040
- continues: false,
8041
- labels: new Set(),
8042
- returnYield: true
8043
- };
8044
- if (this.body.hasEffects(context))
8045
- return true;
8046
- context.ignore = ignore;
8047
- context.brokenFlow = brokenFlow;
8048
8085
  return false;
8049
8086
  }
8050
8087
  include(context, includeChildrenRecursively) {
8051
8088
  this.included = true;
8052
- for (const param of this.params) {
8053
- if (!(param instanceof Identifier)) {
8054
- param.include(context, includeChildrenRecursively);
8055
- }
8056
- }
8057
8089
  const { brokenFlow } = context;
8058
8090
  context.brokenFlow = BROKEN_FLOW_NONE;
8059
8091
  this.body.include(context, includeChildrenRecursively);
@@ -8078,7 +8110,50 @@ class ArrowFunctionExpression extends NodeBase {
8078
8110
  super.parseNode(esTreeNode);
8079
8111
  }
8080
8112
  }
8081
- ArrowFunctionExpression.prototype.preventChildBlockScope = true;
8113
+ FunctionBase.prototype.preventChildBlockScope = true;
8114
+
8115
+ class ArrowFunctionExpression extends FunctionBase {
8116
+ constructor() {
8117
+ super(...arguments);
8118
+ this.objectEntity = null;
8119
+ }
8120
+ createScope(parentScope) {
8121
+ this.scope = new ReturnValueScope(parentScope, this.context);
8122
+ }
8123
+ hasEffects() {
8124
+ return false;
8125
+ }
8126
+ hasEffectsWhenCalledAtPath(path, callOptions, context) {
8127
+ if (super.hasEffectsWhenCalledAtPath(path, callOptions, context))
8128
+ return true;
8129
+ const { ignore, brokenFlow } = context;
8130
+ context.ignore = {
8131
+ breaks: false,
8132
+ continues: false,
8133
+ labels: new Set(),
8134
+ returnYield: true
8135
+ };
8136
+ if (this.body.hasEffects(context))
8137
+ return true;
8138
+ context.ignore = ignore;
8139
+ context.brokenFlow = brokenFlow;
8140
+ return false;
8141
+ }
8142
+ include(context, includeChildrenRecursively) {
8143
+ super.include(context, includeChildrenRecursively);
8144
+ for (const param of this.params) {
8145
+ if (!(param instanceof Identifier)) {
8146
+ param.include(context, includeChildrenRecursively);
8147
+ }
8148
+ }
8149
+ }
8150
+ getObjectEntity() {
8151
+ if (this.objectEntity !== null) {
8152
+ return this.objectEntity;
8153
+ }
8154
+ return (this.objectEntity = new ObjectEntity([], OBJECT_PROTOTYPE));
8155
+ }
8156
+ }
8082
8157
 
8083
8158
  function getSystemExportStatement(exportedVariables, { exportNamesByVariable, snippets: { _, getObject, getPropertyAccess } }, modifier = '') {
8084
8159
  if (exportedVariables.length === 1 &&
@@ -8372,85 +8447,26 @@ class FunctionScope extends ReturnValueScope {
8372
8447
  }
8373
8448
  }
8374
8449
 
8375
- class FunctionNode extends NodeBase {
8450
+ class FunctionNode extends FunctionBase {
8376
8451
  constructor() {
8377
8452
  super(...arguments);
8378
- this.deoptimizedReturn = false;
8379
- this.isPrototypeDeoptimized = false;
8453
+ this.objectEntity = null;
8380
8454
  }
8381
8455
  createScope(parentScope) {
8382
8456
  this.scope = new FunctionScope(parentScope, this.context);
8383
8457
  }
8384
- deoptimizePath(path) {
8385
- if (path.length === 1) {
8386
- if (path[0] === 'prototype') {
8387
- this.isPrototypeDeoptimized = true;
8388
- }
8389
- else if (path[0] === UnknownKey) {
8390
- this.isPrototypeDeoptimized = true;
8391
- // A reassignment of UNKNOWN_PATH is considered equivalent to having lost track
8392
- // which means the return expression needs to be reassigned as well
8393
- this.scope.getReturnExpression().deoptimizePath(UNKNOWN_PATH);
8394
- }
8395
- }
8396
- }
8397
- // TODO for completeness, we should also track other events here
8398
- deoptimizeThisOnEventAtPath(event, path, thisParameter) {
8399
- if (event === EVENT_CALLED) {
8400
- if (path.length > 0) {
8401
- thisParameter.deoptimizePath(UNKNOWN_PATH);
8402
- }
8403
- else {
8404
- this.scope.thisVariable.addEntityToBeDeoptimized(thisParameter);
8405
- }
8406
- }
8407
- }
8408
- getReturnExpressionWhenCalledAtPath(path) {
8409
- if (path.length !== 0) {
8410
- return UNKNOWN_EXPRESSION;
8411
- }
8412
- if (this.async) {
8413
- if (!this.deoptimizedReturn) {
8414
- this.deoptimizedReturn = true;
8415
- this.scope.getReturnExpression().deoptimizePath(UNKNOWN_PATH);
8416
- this.context.requestTreeshakingPass();
8417
- }
8418
- return UNKNOWN_EXPRESSION;
8458
+ deoptimizeThisOnEventAtPath(event, path, thisParameter, recursionTracker) {
8459
+ super.deoptimizeThisOnEventAtPath(event, path, thisParameter, recursionTracker);
8460
+ if (event === EVENT_CALLED && path.length === 0) {
8461
+ this.scope.thisVariable.addEntityToBeDeoptimized(thisParameter);
8419
8462
  }
8420
- return this.scope.getReturnExpression();
8421
8463
  }
8422
8464
  hasEffects() {
8423
8465
  return this.id !== null && this.id.hasEffects();
8424
8466
  }
8425
- hasEffectsWhenAccessedAtPath(path) {
8426
- if (path.length <= 1)
8427
- return false;
8428
- return path.length > 2 || path[0] !== 'prototype' || this.isPrototypeDeoptimized;
8429
- }
8430
- hasEffectsWhenAssignedAtPath(path) {
8431
- if (path.length <= 1) {
8432
- return false;
8433
- }
8434
- return path.length > 2 || path[0] !== 'prototype' || this.isPrototypeDeoptimized;
8435
- }
8436
8467
  hasEffectsWhenCalledAtPath(path, callOptions, context) {
8437
- if (path.length > 0)
8468
+ if (super.hasEffectsWhenCalledAtPath(path, callOptions, context))
8438
8469
  return true;
8439
- if (this.async) {
8440
- const { propertyReadSideEffects } = this.context.options
8441
- .treeshake;
8442
- const returnExpression = this.scope.getReturnExpression();
8443
- if (returnExpression.hasEffectsWhenCalledAtPath(['then'], { args: NO_ARGS, thisParam: null, withNew: false }, context) ||
8444
- (propertyReadSideEffects &&
8445
- (propertyReadSideEffects === 'always' ||
8446
- returnExpression.hasEffectsWhenAccessedAtPath(['then'], context)))) {
8447
- return true;
8448
- }
8449
- }
8450
- for (const param of this.params) {
8451
- if (param.hasEffects(context))
8452
- return true;
8453
- }
8454
8470
  const thisInit = context.replacedVariableInits.get(this.scope.thisVariable);
8455
8471
  context.replacedVariableInits.set(this.scope.thisVariable, callOptions.withNew
8456
8472
  ? new ObjectEntity(Object.create(null), OBJECT_PROTOTYPE)
@@ -8475,7 +8491,7 @@ class FunctionNode extends NodeBase {
8475
8491
  return false;
8476
8492
  }
8477
8493
  include(context, includeChildrenRecursively) {
8478
- this.included = true;
8494
+ super.include(context, includeChildrenRecursively);
8479
8495
  if (this.id)
8480
8496
  this.id.include();
8481
8497
  const hasArguments = this.scope.argumentsVariable.included;
@@ -8484,27 +8500,25 @@ class FunctionNode extends NodeBase {
8484
8500
  param.include(context, includeChildrenRecursively);
8485
8501
  }
8486
8502
  }
8487
- const { brokenFlow } = context;
8488
- context.brokenFlow = BROKEN_FLOW_NONE;
8489
- this.body.include(context, includeChildrenRecursively);
8490
- context.brokenFlow = brokenFlow;
8491
- }
8492
- includeCallArguments(context, args) {
8493
- this.scope.includeCallArguments(context, args);
8494
8503
  }
8495
8504
  initialise() {
8496
- if (this.id !== null) {
8497
- this.id.declare('function', this);
8498
- }
8499
- this.scope.addParameterVariables(this.params.map(param => param.declare('parameter', UNKNOWN_EXPRESSION)), this.params[this.params.length - 1] instanceof RestElement);
8500
- this.body.addImplicitReturnExpressionToScope();
8505
+ var _a;
8506
+ super.initialise();
8507
+ (_a = this.id) === null || _a === void 0 ? void 0 : _a.declare('function', this);
8501
8508
  }
8502
- parseNode(esTreeNode) {
8503
- this.body = new BlockStatement(esTreeNode.body, this, this.scope.hoistedBodyVarScope);
8504
- super.parseNode(esTreeNode);
8509
+ getObjectEntity() {
8510
+ if (this.objectEntity !== null) {
8511
+ return this.objectEntity;
8512
+ }
8513
+ return (this.objectEntity = new ObjectEntity([
8514
+ {
8515
+ key: 'prototype',
8516
+ kind: 'init',
8517
+ property: new ObjectEntity([], OBJECT_PROTOTYPE)
8518
+ }
8519
+ ], OBJECT_PROTOTYPE));
8505
8520
  }
8506
8521
  }
8507
- FunctionNode.prototype.preventChildBlockScope = true;
8508
8522
 
8509
8523
  class AwaitExpression extends NodeBase {
8510
8524
  constructor() {
@@ -8754,7 +8768,11 @@ class MemberExpression extends NodeBase {
8754
8768
  }
8755
8769
  else if (!this.replacement) {
8756
8770
  if (path.length < MAX_PATH_DEPTH) {
8757
- this.object.deoptimizePath([this.getPropertyKey(), ...path]);
8771
+ const propertyKey = this.getPropertyKey();
8772
+ this.object.deoptimizePath([
8773
+ propertyKey === UnknownKey ? UnknownNonAccessorKey : propertyKey,
8774
+ ...path
8775
+ ]);
8758
8776
  }
8759
8777
  }
8760
8778
  }