@rollup/wasm-node 4.16.3 → 4.17.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 v4.16.3
4
- Tue, 23 Apr 2024 05:12:04 GMT - commit b9a62fd4cf28538d7c3b268eb25e709b45d44cce
3
+ Rollup.js v4.17.0
4
+ Sat, 27 Apr 2024 11:29:22 GMT - commit 91352494fc722bcd5e8e922cd1497b34aec57a67
5
5
 
6
6
  https://github.com/rollup/rollup
7
7
 
@@ -31,7 +31,7 @@ function _interopNamespaceDefault(e) {
31
31
 
32
32
  const tty__namespace = /*#__PURE__*/_interopNamespaceDefault(tty);
33
33
 
34
- var version = "4.16.3";
34
+ var version = "4.17.0";
35
35
 
36
36
  function ensureArray$1(items) {
37
37
  if (Array.isArray(items)) {
@@ -3416,7 +3416,6 @@ class Variable extends ExpressionEntity {
3416
3416
  addReference(_identifier) { }
3417
3417
  /**
3418
3418
  * Check if the identifier variable is only used as function call
3419
- * Forward the check to the export default variable if it is only used once
3420
3419
  * @returns true if the variable is only used as function call
3421
3420
  */
3422
3421
  getOnlyFunctionCallUsed() {
@@ -7133,936 +7132,338 @@ class ArrayPattern extends NodeBase {
7133
7132
  }
7134
7133
  }
7135
7134
 
7136
- class LocalVariable extends Variable {
7137
- constructor(name, declarator, init, context, kind) {
7138
- super(name);
7139
- this.init = init;
7140
- this.calledFromTryStatement = false;
7141
- this.additionalInitializers = null;
7142
- this.expressionsToBeDeoptimized = [];
7143
- this.declarations = declarator ? [declarator] : [];
7144
- this.deoptimizationTracker = context.deoptimizationTracker;
7145
- this.module = context.module;
7146
- this.kind = kind;
7147
- }
7148
- addDeclaration(identifier, init) {
7149
- this.declarations.push(identifier);
7150
- this.markInitializersForDeoptimization().push(init);
7151
- }
7152
- consolidateInitializers() {
7153
- if (this.additionalInitializers) {
7154
- for (const initializer of this.additionalInitializers) {
7155
- initializer.deoptimizePath(UNKNOWN_PATH);
7156
- }
7157
- this.additionalInitializers = null;
7158
- }
7159
- }
7160
- deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker) {
7161
- if (this.isReassigned) {
7162
- deoptimizeInteraction(interaction);
7163
- return;
7164
- }
7165
- recursionTracker.withTrackedEntityAtPath(path, this.init, () => this.init.deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker), undefined);
7166
- }
7167
- deoptimizePath(path) {
7168
- if (this.isReassigned ||
7169
- this.deoptimizationTracker.trackEntityAtPathAndGetIfTracked(path, this)) {
7170
- return;
7171
- }
7172
- if (path.length === 0) {
7173
- this.markReassigned();
7174
- const expressionsToBeDeoptimized = this.expressionsToBeDeoptimized;
7175
- this.expressionsToBeDeoptimized = parseAst_js.EMPTY_ARRAY;
7176
- for (const expression of expressionsToBeDeoptimized) {
7177
- expression.deoptimizeCache();
7178
- }
7179
- this.init.deoptimizePath(UNKNOWN_PATH);
7180
- }
7181
- else {
7182
- this.init.deoptimizePath(path);
7183
- }
7184
- }
7185
- getLiteralValueAtPath(path, recursionTracker, origin) {
7186
- if (this.isReassigned) {
7187
- return UnknownValue;
7188
- }
7189
- return recursionTracker.withTrackedEntityAtPath(path, this.init, () => {
7190
- this.expressionsToBeDeoptimized.push(origin);
7191
- return this.init.getLiteralValueAtPath(path, recursionTracker, origin);
7192
- }, UnknownValue);
7193
- }
7194
- getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin) {
7195
- if (this.isReassigned) {
7196
- return UNKNOWN_RETURN_EXPRESSION;
7197
- }
7198
- return recursionTracker.withTrackedEntityAtPath(path, this.init, () => {
7199
- this.expressionsToBeDeoptimized.push(origin);
7200
- return this.init.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin);
7201
- }, UNKNOWN_RETURN_EXPRESSION);
7202
- }
7203
- hasEffectsOnInteractionAtPath(path, interaction, context) {
7204
- switch (interaction.type) {
7205
- case INTERACTION_ACCESSED: {
7206
- if (this.isReassigned)
7207
- return true;
7208
- return (!context.accessed.trackEntityAtPathAndGetIfTracked(path, this) &&
7209
- this.init.hasEffectsOnInteractionAtPath(path, interaction, context));
7210
- }
7211
- case INTERACTION_ASSIGNED: {
7212
- if (this.included)
7213
- return true;
7214
- if (path.length === 0)
7215
- return false;
7216
- if (this.isReassigned)
7217
- return true;
7218
- return (!context.assigned.trackEntityAtPathAndGetIfTracked(path, this) &&
7219
- this.init.hasEffectsOnInteractionAtPath(path, interaction, context));
7220
- }
7221
- case INTERACTION_CALLED: {
7222
- if (this.isReassigned)
7223
- return true;
7224
- return (!(interaction.withNew ? context.instantiated : context.called).trackEntityAtPathAndGetIfTracked(path, interaction.args, this) &&
7225
- this.init.hasEffectsOnInteractionAtPath(path, interaction, context));
7226
- }
7227
- }
7228
- }
7229
- include() {
7230
- if (!this.included) {
7231
- super.include();
7232
- for (const declaration of this.declarations) {
7233
- // If node is a default export, it can save a tree-shaking run to include the full declaration now
7234
- if (!declaration.included)
7235
- declaration.include(createInclusionContext(), false);
7236
- let node = declaration.parent;
7237
- while (!node.included) {
7238
- // We do not want to properly include parents in case they are part of a dead branch
7239
- // in which case .include() might pull in more dead code
7240
- node.included = true;
7241
- if (node.type === parseAst_js.Program)
7242
- break;
7243
- node = node.parent;
7244
- }
7245
- }
7135
+ /** @typedef { import('estree').Node} Node */
7136
+ /** @typedef {Node | {
7137
+ * type: 'PropertyDefinition';
7138
+ * computed: boolean;
7139
+ * value: Node
7140
+ * }} NodeWithPropertyDefinition */
7141
+
7142
+ /**
7143
+ *
7144
+ * @param {NodeWithPropertyDefinition} node
7145
+ * @param {NodeWithPropertyDefinition} parent
7146
+ * @returns {boolean}
7147
+ */
7148
+ function is_reference (node, parent) {
7149
+ if (node.type === 'MemberExpression') {
7150
+ return !node.computed && is_reference(node.object, node);
7151
+ }
7152
+
7153
+ if (node.type === 'Identifier') {
7154
+ if (!parent) return true;
7155
+
7156
+ switch (parent.type) {
7157
+ // disregard `bar` in `foo.bar`
7158
+ case 'MemberExpression': return parent.computed || node === parent.object;
7159
+
7160
+ // disregard the `foo` in `class {foo(){}}` but keep it in `class {[foo](){}}`
7161
+ case 'MethodDefinition': return parent.computed;
7162
+
7163
+ // disregard the `foo` in `class {foo=bar}` but keep it in `class {[foo]=bar}` and `class {bar=foo}`
7164
+ case 'PropertyDefinition': return parent.computed || node === parent.value;
7165
+
7166
+ // disregard the `bar` in `{ bar: foo }`, but keep it in `{ [bar]: foo }`
7167
+ case 'Property': return parent.computed || node === parent.value;
7168
+
7169
+ // disregard the `bar` in `export { foo as bar }` or
7170
+ // the foo in `import { foo as bar }`
7171
+ case 'ExportSpecifier':
7172
+ case 'ImportSpecifier': return node === parent.local;
7173
+
7174
+ // disregard the `foo` in `foo: while (...) { ... break foo; ... continue foo;}`
7175
+ case 'LabeledStatement':
7176
+ case 'BreakStatement':
7177
+ case 'ContinueStatement': return false;
7178
+ default: return true;
7179
+ }
7180
+ }
7181
+
7182
+ return false;
7183
+ }
7184
+
7185
+ const PureFunctionKey = Symbol('PureFunction');
7186
+ const getPureFunctions = ({ treeshake }) => {
7187
+ const pureFunctions = Object.create(null);
7188
+ for (const functionName of treeshake ? treeshake.manualPureFunctions : []) {
7189
+ let currentFunctions = pureFunctions;
7190
+ for (const pathSegment of functionName.split('.')) {
7191
+ currentFunctions = currentFunctions[pathSegment] ||= Object.create(null);
7246
7192
  }
7193
+ currentFunctions[PureFunctionKey] = true;
7247
7194
  }
7248
- includeCallArguments(context, parameters) {
7249
- if (this.isReassigned || context.includedCallArguments.has(this.init)) {
7250
- for (const argument of parameters) {
7251
- argument.include(context, false);
7252
- }
7253
- }
7254
- else {
7255
- context.includedCallArguments.add(this.init);
7256
- this.init.includeCallArguments(context, parameters);
7257
- context.includedCallArguments.delete(this.init);
7258
- }
7195
+ return pureFunctions;
7196
+ };
7197
+
7198
+ /* eslint sort-keys: "off" */
7199
+ const ValueProperties = Symbol('Value Properties');
7200
+ const getTruthyLiteralValue = () => UnknownTruthyValue;
7201
+ const returnFalse = () => false;
7202
+ const returnTrue = () => true;
7203
+ const PURE = {
7204
+ deoptimizeArgumentsOnCall: doNothing,
7205
+ getLiteralValue: getTruthyLiteralValue,
7206
+ hasEffectsWhenCalled: returnFalse
7207
+ };
7208
+ const IMPURE = {
7209
+ deoptimizeArgumentsOnCall: doNothing,
7210
+ getLiteralValue: getTruthyLiteralValue,
7211
+ hasEffectsWhenCalled: returnTrue
7212
+ };
7213
+ const PURE_WITH_ARRAY = {
7214
+ deoptimizeArgumentsOnCall: doNothing,
7215
+ getLiteralValue: getTruthyLiteralValue,
7216
+ hasEffectsWhenCalled({ args }) {
7217
+ return args.length > 1 && !(args[1] instanceof ArrayExpression);
7259
7218
  }
7260
- markCalledFromTryStatement() {
7261
- this.calledFromTryStatement = true;
7219
+ };
7220
+ const GETTER_ACCESS = {
7221
+ deoptimizeArgumentsOnCall: doNothing,
7222
+ getLiteralValue: getTruthyLiteralValue,
7223
+ hasEffectsWhenCalled({ args }, context) {
7224
+ const [_thisArgument, firstArgument] = args;
7225
+ return (!(firstArgument instanceof ExpressionEntity) ||
7226
+ firstArgument.hasEffectsOnInteractionAtPath(UNKNOWN_PATH, NODE_INTERACTION_UNKNOWN_ACCESS, context));
7262
7227
  }
7263
- markInitializersForDeoptimization() {
7264
- if (this.additionalInitializers === null) {
7265
- this.additionalInitializers = [this.init];
7266
- this.init = UNKNOWN_EXPRESSION;
7267
- this.markReassigned();
7228
+ };
7229
+ // We use shortened variables to reduce file size here
7230
+ /* OBJECT */
7231
+ const O = {
7232
+ __proto__: null,
7233
+ [ValueProperties]: IMPURE
7234
+ };
7235
+ /* PURE FUNCTION */
7236
+ const PF = {
7237
+ __proto__: null,
7238
+ [ValueProperties]: PURE
7239
+ };
7240
+ /* PURE FUNCTION IF FIRST ARG DOES NOT CONTAIN A GETTER */
7241
+ const PF_NO_GETTER = {
7242
+ __proto__: null,
7243
+ [ValueProperties]: GETTER_ACCESS
7244
+ };
7245
+ /* FUNCTION THAT MUTATES FIRST ARG WITHOUT TRIGGERING ACCESSORS */
7246
+ const MUTATES_ARG_WITHOUT_ACCESSOR = {
7247
+ __proto__: null,
7248
+ [ValueProperties]: {
7249
+ deoptimizeArgumentsOnCall({ args: [, firstArgument] }) {
7250
+ firstArgument?.deoptimizePath(UNKNOWN_PATH);
7251
+ },
7252
+ getLiteralValue: getTruthyLiteralValue,
7253
+ hasEffectsWhenCalled({ args }, context) {
7254
+ return (args.length <= 1 ||
7255
+ args[1].hasEffectsOnInteractionAtPath(UNKNOWN_NON_ACCESSOR_PATH, NODE_INTERACTION_UNKNOWN_ASSIGNMENT, context));
7268
7256
  }
7269
- return this.additionalInitializers;
7270
7257
  }
7271
- }
7272
-
7273
- const MAX_TRACKED_INTERACTIONS = 20;
7274
- const NO_INTERACTIONS = parseAst_js.EMPTY_ARRAY;
7275
- const UNKNOWN_DEOPTIMIZED_FIELD = new Set([UnknownKey]);
7276
- const EMPTY_PATH_TRACKER = new PathTracker();
7277
- const UNKNOWN_DEOPTIMIZED_ENTITY = new Set([UNKNOWN_EXPRESSION]);
7278
- class ParameterVariable extends LocalVariable {
7279
- constructor(name, declarator, context) {
7280
- super(name, declarator, UNKNOWN_EXPRESSION, context, 'parameter');
7281
- this.deoptimizationInteractions = [];
7282
- this.deoptimizations = new PathTracker();
7283
- this.deoptimizedFields = new Set();
7284
- this.entitiesToBeDeoptimized = new Set();
7285
- this.knownExpressionsToBeDeoptimized = [];
7286
- this.knownValue = UNKNOWN_EXPRESSION;
7287
- }
7288
- addEntityToBeDeoptimized(entity) {
7289
- if (entity === UNKNOWN_EXPRESSION) {
7290
- // As unknown expressions fully deoptimize all interactions, we can clear
7291
- // the interaction cache at this point provided we keep this optimization
7292
- // in mind when adding new interactions
7293
- if (!this.entitiesToBeDeoptimized.has(UNKNOWN_EXPRESSION)) {
7294
- this.entitiesToBeDeoptimized.add(UNKNOWN_EXPRESSION);
7295
- for (const { interaction } of this.deoptimizationInteractions) {
7296
- deoptimizeInteraction(interaction);
7297
- }
7298
- this.deoptimizationInteractions = NO_INTERACTIONS;
7299
- }
7300
- }
7301
- else if (this.deoptimizedFields.has(UnknownKey)) {
7302
- // This means that we already deoptimized all interactions and no longer
7303
- // track them
7304
- entity.deoptimizePath(UNKNOWN_PATH);
7305
- }
7306
- else if (!this.entitiesToBeDeoptimized.has(entity)) {
7307
- this.entitiesToBeDeoptimized.add(entity);
7308
- for (const field of this.deoptimizedFields) {
7309
- entity.deoptimizePath([field]);
7310
- }
7311
- for (const { interaction, path } of this.deoptimizationInteractions) {
7312
- entity.deoptimizeArgumentsOnInteractionAtPath(interaction, path, SHARED_RECURSION_TRACKER);
7313
- }
7314
- }
7315
- }
7316
- markReassigned() {
7317
- if (this.isReassigned) {
7318
- return;
7319
- }
7320
- super.markReassigned();
7321
- for (const expression of this.knownExpressionsToBeDeoptimized) {
7322
- expression.deoptimizeCache();
7323
- }
7324
- this.knownExpressionsToBeDeoptimized = [];
7325
- }
7326
- /**
7327
- * If we are sure about the value of this parameter, we can set it here.
7328
- * It can be a literal or the only possible value of the parameter.
7329
- * an undefined value means that the parameter is not known.
7330
- * @param value The known value of the parameter to be set.
7331
- */
7332
- setKnownValue(value) {
7333
- if (this.isReassigned) {
7334
- return;
7335
- }
7336
- if (this.knownValue !== value) {
7337
- for (const expression of this.knownExpressionsToBeDeoptimized) {
7338
- expression.deoptimizeCache();
7339
- }
7340
- this.knownExpressionsToBeDeoptimized = [];
7341
- }
7342
- this.knownValue = value;
7343
- }
7344
- getLiteralValueAtPath(path, recursionTracker, origin) {
7345
- if (this.isReassigned) {
7346
- return UnknownValue;
7347
- }
7348
- this.knownExpressionsToBeDeoptimized.push(origin);
7349
- return recursionTracker.withTrackedEntityAtPath(path, this.knownValue, () => this.knownValue.getLiteralValueAtPath(path, recursionTracker, origin), UnknownValue);
7350
- }
7351
- hasEffectsOnInteractionAtPath(path, interaction, context) {
7352
- // assigned is a bit different, since the value has a new name (the parameter)
7353
- return interaction.type === INTERACTION_ASSIGNED
7354
- ? super.hasEffectsOnInteractionAtPath(path, interaction, context)
7355
- : this.knownValue.hasEffectsOnInteractionAtPath(path, interaction, context);
7356
- }
7357
- deoptimizeArgumentsOnInteractionAtPath(interaction, path) {
7358
- // For performance reasons, we fully deoptimize all deeper interactions
7359
- if (path.length >= 2 ||
7360
- this.entitiesToBeDeoptimized.has(UNKNOWN_EXPRESSION) ||
7361
- this.deoptimizationInteractions.length >= MAX_TRACKED_INTERACTIONS ||
7362
- (path.length === 1 &&
7363
- (this.deoptimizedFields.has(UnknownKey) ||
7364
- (interaction.type === INTERACTION_CALLED && this.deoptimizedFields.has(path[0]))))) {
7365
- deoptimizeInteraction(interaction);
7366
- return;
7367
- }
7368
- if (!this.deoptimizations.trackEntityAtPathAndGetIfTracked(path, interaction.args)) {
7369
- for (const entity of this.entitiesToBeDeoptimized) {
7370
- entity.deoptimizeArgumentsOnInteractionAtPath(interaction, path, SHARED_RECURSION_TRACKER);
7371
- }
7372
- if (!this.entitiesToBeDeoptimized.has(UNKNOWN_EXPRESSION)) {
7373
- this.deoptimizationInteractions.push({
7374
- interaction,
7375
- path
7376
- });
7377
- }
7378
- }
7379
- }
7380
- deoptimizePath(path) {
7381
- if (path.length === 0) {
7382
- this.markReassigned();
7383
- return;
7384
- }
7385
- if (this.deoptimizedFields.has(UnknownKey)) {
7386
- return;
7387
- }
7388
- const key = path[0];
7389
- if (this.deoptimizedFields.has(key)) {
7390
- return;
7391
- }
7392
- this.deoptimizedFields.add(key);
7393
- for (const entity of this.entitiesToBeDeoptimized) {
7394
- // We do not need a recursion tracker here as we already track whether
7395
- // this field is deoptimized
7396
- entity.deoptimizePath([key]);
7397
- }
7398
- if (key === UnknownKey) {
7399
- // save some memory
7400
- this.deoptimizationInteractions = NO_INTERACTIONS;
7401
- this.deoptimizations = EMPTY_PATH_TRACKER;
7402
- this.deoptimizedFields = UNKNOWN_DEOPTIMIZED_FIELD;
7403
- this.entitiesToBeDeoptimized = UNKNOWN_DEOPTIMIZED_ENTITY;
7404
- }
7405
- }
7406
- getReturnExpressionWhenCalledAtPath(path) {
7407
- // We deoptimize everything that is called as that will trivially deoptimize
7408
- // the corresponding return expressions as well and avoid badly performing
7409
- // and complicated alternatives
7410
- if (path.length === 0) {
7411
- this.deoptimizePath(UNKNOWN_PATH);
7412
- }
7413
- else if (!this.deoptimizedFields.has(path[0])) {
7414
- this.deoptimizePath([path[0]]);
7415
- }
7416
- return UNKNOWN_RETURN_EXPRESSION;
7417
- }
7418
- }
7419
-
7420
- function getSafeName(baseName, usedNames, forbiddenNames) {
7421
- let safeName = baseName;
7422
- let count = 1;
7423
- while (usedNames.has(safeName) || RESERVED_NAMES.has(safeName) || forbiddenNames?.has(safeName)) {
7424
- safeName = `${baseName}$${toBase64(count++)}`;
7425
- }
7426
- usedNames.add(safeName);
7427
- return safeName;
7428
- }
7429
-
7430
- class Scope {
7431
- constructor() {
7432
- this.children = [];
7433
- this.variables = new Map();
7434
- }
7435
- /*
7436
- Redeclaration rules:
7437
- - var can redeclare var
7438
- - in function scopes, function and var can redeclare function and var
7439
- - var is hoisted across scopes, function remains in the scope it is declared
7440
- - var and function can redeclare function parameters, but parameters cannot redeclare parameters
7441
- - function cannot redeclare catch scope parameters
7442
- - var can redeclare catch scope parameters in a way
7443
- - if the parameter is an identifier and not a pattern
7444
- - then the variable is still declared in the hoisted outer scope, but the initializer is assigned to the parameter
7445
- - const, let, class, and function except in the cases above cannot redeclare anything
7446
- */
7447
- addDeclaration(identifier, context, init, kind) {
7448
- const name = identifier.name;
7449
- const existingVariable = this.hoistedVariables?.get(name) || this.variables.get(name);
7450
- if (existingVariable) {
7451
- const existingKind = existingVariable.kind;
7452
- if (kind === 'var' && existingKind === 'var') {
7453
- existingVariable.addDeclaration(identifier, init);
7454
- return existingVariable;
7455
- }
7456
- context.error(parseAst_js.logRedeclarationError(name), identifier.start);
7457
- }
7458
- const newVariable = new LocalVariable(identifier.name, identifier, init, context, kind);
7459
- this.variables.set(name, newVariable);
7460
- return newVariable;
7461
- }
7462
- addHoistedVariable(name, variable) {
7463
- (this.hoistedVariables ||= new Map()).set(name, variable);
7464
- }
7465
- contains(name) {
7466
- return this.variables.has(name);
7467
- }
7468
- findVariable(_name) {
7469
- /* istanbul ignore next */
7470
- throw new Error('Internal Error: findVariable needs to be implemented by a subclass');
7471
- }
7472
- }
7473
-
7474
- class ChildScope extends Scope {
7475
- constructor(parent, context) {
7476
- super();
7477
- this.parent = parent;
7478
- this.context = context;
7479
- this.accessedOutsideVariables = new Map();
7480
- parent.children.push(this);
7481
- }
7482
- addAccessedDynamicImport(importExpression) {
7483
- (this.accessedDynamicImports || (this.accessedDynamicImports = new Set())).add(importExpression);
7484
- if (this.parent instanceof ChildScope) {
7485
- this.parent.addAccessedDynamicImport(importExpression);
7486
- }
7487
- }
7488
- addAccessedGlobals(globals, accessedGlobalsByScope) {
7489
- const accessedGlobals = accessedGlobalsByScope.get(this) || new Set();
7490
- for (const name of globals) {
7491
- accessedGlobals.add(name);
7492
- }
7493
- accessedGlobalsByScope.set(this, accessedGlobals);
7494
- if (this.parent instanceof ChildScope) {
7495
- this.parent.addAccessedGlobals(globals, accessedGlobalsByScope);
7496
- }
7497
- }
7498
- addNamespaceMemberAccess(name, variable) {
7499
- this.accessedOutsideVariables.set(name, variable);
7500
- this.parent.addNamespaceMemberAccess(name, variable);
7501
- }
7502
- addReturnExpression(expression) {
7503
- this.parent instanceof ChildScope && this.parent.addReturnExpression(expression);
7504
- }
7505
- addUsedOutsideNames(usedNames, format, exportNamesByVariable, accessedGlobalsByScope) {
7506
- for (const variable of this.accessedOutsideVariables.values()) {
7507
- if (variable.included) {
7508
- usedNames.add(variable.getBaseVariableName());
7509
- if (format === 'system' && exportNamesByVariable.has(variable)) {
7510
- usedNames.add('exports');
7511
- }
7512
- }
7513
- }
7514
- const accessedGlobals = accessedGlobalsByScope.get(this);
7515
- if (accessedGlobals) {
7516
- for (const name of accessedGlobals) {
7517
- usedNames.add(name);
7518
- }
7519
- }
7520
- }
7521
- contains(name) {
7522
- return this.variables.has(name) || this.parent.contains(name);
7523
- }
7524
- deconflict(format, exportNamesByVariable, accessedGlobalsByScope) {
7525
- const usedNames = new Set();
7526
- this.addUsedOutsideNames(usedNames, format, exportNamesByVariable, accessedGlobalsByScope);
7527
- if (this.accessedDynamicImports) {
7528
- for (const importExpression of this.accessedDynamicImports) {
7529
- if (importExpression.inlineNamespace) {
7530
- usedNames.add(importExpression.inlineNamespace.getBaseVariableName());
7531
- }
7532
- }
7533
- }
7534
- for (const [name, variable] of this.variables) {
7535
- if (variable.included || variable.alwaysRendered) {
7536
- variable.setRenderNames(null, getSafeName(name, usedNames, variable.forbiddenNames));
7537
- }
7538
- }
7539
- for (const scope of this.children) {
7540
- scope.deconflict(format, exportNamesByVariable, accessedGlobalsByScope);
7541
- }
7542
- }
7543
- findLexicalBoundary() {
7544
- return this.parent.findLexicalBoundary();
7545
- }
7546
- findVariable(name) {
7547
- const knownVariable = this.variables.get(name) || this.accessedOutsideVariables.get(name);
7548
- if (knownVariable) {
7549
- return knownVariable;
7550
- }
7551
- const variable = this.parent.findVariable(name);
7552
- this.accessedOutsideVariables.set(name, variable);
7553
- return variable;
7554
- }
7555
- }
7556
-
7557
- class CatchBodyScope extends ChildScope {
7558
- constructor(parent) {
7559
- super(parent, parent.context);
7560
- this.parent = parent;
7561
- }
7562
- addDeclaration(identifier, context, init, kind) {
7563
- if (kind === 'var') {
7564
- const name = identifier.name;
7565
- const existingVariable = this.hoistedVariables?.get(name) || this.variables.get(name);
7566
- if (existingVariable) {
7567
- const existingKind = existingVariable.kind;
7568
- if (existingKind === 'parameter' &&
7569
- // If this is a destructured parameter, it is forbidden to redeclare
7570
- existingVariable.declarations[0].parent.type === parseAst_js.CatchClause) {
7571
- // If this is a var with the same name as the catch scope parameter,
7572
- // the assignment actually goes to the parameter and the var is
7573
- // hoisted without assignment. Locally, it is shadowed by the
7574
- // parameter
7575
- const declaredVariable = this.parent.parent.addDeclaration(identifier, context, UNDEFINED_EXPRESSION, kind);
7576
- // To avoid the need to rewrite the declaration, we link the variable
7577
- // names. If we ever implement a logic that splits initialization and
7578
- // assignment for hoisted vars, the "renderLikeHoisted" logic can be
7579
- // removed again.
7580
- // We do not need to check whether there already is a linked
7581
- // variable because then declaredVariable would be that linked
7582
- // variable.
7583
- existingVariable.renderLikeHoisted(declaredVariable);
7584
- this.addHoistedVariable(name, declaredVariable);
7585
- return declaredVariable;
7586
- }
7587
- if (existingKind === 'var') {
7588
- existingVariable.addDeclaration(identifier, init);
7589
- return existingVariable;
7590
- }
7591
- return context.error(parseAst_js.logRedeclarationError(name), identifier.start);
7592
- }
7593
- // We only add parameters to parameter scopes
7594
- const declaredVariable = this.parent.parent.addDeclaration(identifier, context, init, kind);
7595
- // Necessary to make sure the init is deoptimized for conditional declarations.
7596
- // We cannot call deoptimizePath here.
7597
- declaredVariable.markInitializersForDeoptimization();
7598
- // We add the variable to this and all parent scopes to reliably detect conflicts
7599
- this.addHoistedVariable(name, declaredVariable);
7600
- return declaredVariable;
7601
- }
7602
- return super.addDeclaration(identifier, context, init, kind);
7603
- }
7604
- }
7605
-
7606
- class FunctionBodyScope extends ChildScope {
7607
- constructor(parent) {
7608
- super(parent, parent.context);
7609
- }
7610
- // There is stuff that is only allowed in function scopes, i.e. functions can
7611
- // be redeclared, functions and var can redeclare each other
7612
- addDeclaration(identifier, context, init, kind) {
7613
- const name = identifier.name;
7614
- const existingVariable = this.hoistedVariables?.get(name) || this.variables.get(name);
7615
- if (existingVariable) {
7616
- const existingKind = existingVariable.kind;
7617
- if ((kind === 'var' || kind === 'function') &&
7618
- (existingKind === 'var' || existingKind === 'function' || existingKind === 'parameter')) {
7619
- existingVariable.addDeclaration(identifier, init);
7620
- return existingVariable;
7621
- }
7622
- context.error(parseAst_js.logRedeclarationError(name), identifier.start);
7623
- }
7624
- const newVariable = new LocalVariable(identifier.name, identifier, init, context, kind);
7625
- this.variables.set(name, newVariable);
7626
- return newVariable;
7627
- }
7628
- }
7629
-
7630
- class ParameterScope extends ChildScope {
7631
- constructor(parent, isCatchScope) {
7632
- super(parent, parent.context);
7633
- this.parameters = [];
7634
- this.hasRest = false;
7635
- this.bodyScope = isCatchScope ? new CatchBodyScope(this) : new FunctionBodyScope(this);
7636
- }
7637
- /**
7638
- * Adds a parameter to this scope. Parameters must be added in the correct
7639
- * order, i.e. from left to right.
7640
- */
7641
- addParameterDeclaration(identifier) {
7642
- const { name, start } = identifier;
7643
- const existingParameter = this.variables.get(name);
7644
- if (existingParameter) {
7645
- return this.context.error(parseAst_js.logDuplicateArgumentNameError(name), start);
7646
- }
7647
- const variable = new ParameterVariable(name, identifier, this.context);
7648
- this.variables.set(name, variable);
7649
- // We also add it to the body scope to detect name conflicts with local
7650
- // variables. We still need the intermediate scope, though, as parameter
7651
- // defaults are NOT taken from the body scope but from the parameters or
7652
- // outside scope.
7653
- this.bodyScope.addHoistedVariable(name, variable);
7654
- return variable;
7655
- }
7656
- addParameterVariables(parameters, hasRest) {
7657
- this.parameters = parameters;
7658
- for (const parameterList of parameters) {
7659
- for (const parameter of parameterList) {
7660
- parameter.alwaysRendered = true;
7661
- }
7662
- }
7663
- this.hasRest = hasRest;
7664
- }
7665
- includeCallArguments(context, parameters) {
7666
- let calledFromTryStatement = false;
7667
- let argumentIncluded = false;
7668
- const restParameter = this.hasRest && this.parameters[this.parameters.length - 1];
7669
- for (const checkedArgument of parameters) {
7670
- if (checkedArgument instanceof SpreadElement) {
7671
- for (const argument of parameters) {
7672
- argument.include(context, false);
7673
- }
7674
- break;
7675
- }
7676
- }
7677
- for (let index = parameters.length - 1; index >= 0; index--) {
7678
- const parameterVariables = this.parameters[index] || restParameter;
7679
- const argument = parameters[index];
7680
- if (parameterVariables) {
7681
- calledFromTryStatement = false;
7682
- if (parameterVariables.length === 0) {
7683
- // handle empty destructuring
7684
- argumentIncluded = true;
7685
- }
7686
- else {
7687
- for (const variable of parameterVariables) {
7688
- if (variable.included) {
7689
- argumentIncluded = true;
7690
- }
7691
- if (variable.calledFromTryStatement) {
7692
- calledFromTryStatement = true;
7693
- }
7694
- }
7695
- }
7696
- }
7697
- if (!argumentIncluded && argument.shouldBeIncluded(context)) {
7698
- argumentIncluded = true;
7699
- }
7700
- if (argumentIncluded) {
7701
- argument.include(context, calledFromTryStatement);
7702
- }
7703
- }
7704
- }
7705
- }
7706
-
7707
- class ReturnValueScope extends ParameterScope {
7708
- constructor() {
7709
- super(...arguments);
7710
- this.returnExpression = null;
7711
- this.returnExpressions = [];
7712
- }
7713
- addReturnExpression(expression) {
7714
- this.returnExpressions.push(expression);
7715
- }
7716
- getReturnExpression() {
7717
- if (this.returnExpression === null)
7718
- this.updateReturnExpression();
7719
- return this.returnExpression;
7720
- }
7721
- updateReturnExpression() {
7722
- if (this.returnExpressions.length === 1) {
7723
- this.returnExpression = this.returnExpressions[0];
7724
- }
7725
- else {
7726
- this.returnExpression = UNKNOWN_EXPRESSION;
7727
- for (const expression of this.returnExpressions) {
7728
- expression.deoptimizePath(UNKNOWN_PATH);
7729
- }
7730
- }
7731
- }
7732
- }
7733
-
7734
- /** @typedef { import('estree').Node} Node */
7735
- /** @typedef {Node | {
7736
- * type: 'PropertyDefinition';
7737
- * computed: boolean;
7738
- * value: Node
7739
- * }} NodeWithPropertyDefinition */
7740
-
7741
- /**
7742
- *
7743
- * @param {NodeWithPropertyDefinition} node
7744
- * @param {NodeWithPropertyDefinition} parent
7745
- * @returns {boolean}
7746
- */
7747
- function is_reference (node, parent) {
7748
- if (node.type === 'MemberExpression') {
7749
- return !node.computed && is_reference(node.object, node);
7750
- }
7751
-
7752
- if (node.type === 'Identifier') {
7753
- if (!parent) return true;
7754
-
7755
- switch (parent.type) {
7756
- // disregard `bar` in `foo.bar`
7757
- case 'MemberExpression': return parent.computed || node === parent.object;
7758
-
7759
- // disregard the `foo` in `class {foo(){}}` but keep it in `class {[foo](){}}`
7760
- case 'MethodDefinition': return parent.computed;
7761
-
7762
- // disregard the `foo` in `class {foo=bar}` but keep it in `class {[foo]=bar}` and `class {bar=foo}`
7763
- case 'PropertyDefinition': return parent.computed || node === parent.value;
7764
-
7765
- // disregard the `bar` in `{ bar: foo }`, but keep it in `{ [bar]: foo }`
7766
- case 'Property': return parent.computed || node === parent.value;
7767
-
7768
- // disregard the `bar` in `export { foo as bar }` or
7769
- // the foo in `import { foo as bar }`
7770
- case 'ExportSpecifier':
7771
- case 'ImportSpecifier': return node === parent.local;
7772
-
7773
- // disregard the `foo` in `foo: while (...) { ... break foo; ... continue foo;}`
7774
- case 'LabeledStatement':
7775
- case 'BreakStatement':
7776
- case 'ContinueStatement': return false;
7777
- default: return true;
7778
- }
7779
- }
7780
-
7781
- return false;
7782
- }
7783
-
7784
- const PureFunctionKey = Symbol('PureFunction');
7785
- const getPureFunctions = ({ treeshake }) => {
7786
- const pureFunctions = Object.create(null);
7787
- for (const functionName of treeshake ? treeshake.manualPureFunctions : []) {
7788
- let currentFunctions = pureFunctions;
7789
- for (const pathSegment of functionName.split('.')) {
7790
- currentFunctions = currentFunctions[pathSegment] ||= Object.create(null);
7791
- }
7792
- currentFunctions[PureFunctionKey] = true;
7793
- }
7794
- return pureFunctions;
7795
- };
7796
-
7797
- /* eslint sort-keys: "off" */
7798
- const ValueProperties = Symbol('Value Properties');
7799
- const getTruthyLiteralValue = () => UnknownTruthyValue;
7800
- const returnFalse = () => false;
7801
- const returnTrue = () => true;
7802
- const PURE = {
7803
- deoptimizeArgumentsOnCall: doNothing,
7804
- getLiteralValue: getTruthyLiteralValue,
7805
- hasEffectsWhenCalled: returnFalse
7806
- };
7807
- const IMPURE = {
7808
- deoptimizeArgumentsOnCall: doNothing,
7809
- getLiteralValue: getTruthyLiteralValue,
7810
- hasEffectsWhenCalled: returnTrue
7811
- };
7812
- const PURE_WITH_ARRAY = {
7813
- deoptimizeArgumentsOnCall: doNothing,
7814
- getLiteralValue: getTruthyLiteralValue,
7815
- hasEffectsWhenCalled({ args }) {
7816
- return args.length > 1 && !(args[1] instanceof ArrayExpression);
7817
- }
7818
- };
7819
- const GETTER_ACCESS = {
7820
- deoptimizeArgumentsOnCall: doNothing,
7821
- getLiteralValue: getTruthyLiteralValue,
7822
- hasEffectsWhenCalled({ args }, context) {
7823
- const [_thisArgument, firstArgument] = args;
7824
- return (!(firstArgument instanceof ExpressionEntity) ||
7825
- firstArgument.hasEffectsOnInteractionAtPath(UNKNOWN_PATH, NODE_INTERACTION_UNKNOWN_ACCESS, context));
7826
- }
7827
- };
7828
- // We use shortened variables to reduce file size here
7829
- /* OBJECT */
7830
- const O = {
7831
- __proto__: null,
7832
- [ValueProperties]: IMPURE
7833
- };
7834
- /* PURE FUNCTION */
7835
- const PF = {
7836
- __proto__: null,
7837
- [ValueProperties]: PURE
7838
- };
7839
- /* PURE FUNCTION IF FIRST ARG DOES NOT CONTAIN A GETTER */
7840
- const PF_NO_GETTER = {
7841
- __proto__: null,
7842
- [ValueProperties]: GETTER_ACCESS
7843
- };
7844
- /* FUNCTION THAT MUTATES FIRST ARG WITHOUT TRIGGERING ACCESSORS */
7845
- const MUTATES_ARG_WITHOUT_ACCESSOR = {
7846
- __proto__: null,
7847
- [ValueProperties]: {
7848
- deoptimizeArgumentsOnCall({ args: [, firstArgument] }) {
7849
- firstArgument?.deoptimizePath(UNKNOWN_PATH);
7850
- },
7851
- getLiteralValue: getTruthyLiteralValue,
7852
- hasEffectsWhenCalled({ args }, context) {
7853
- return (args.length <= 1 ||
7854
- args[1].hasEffectsOnInteractionAtPath(UNKNOWN_NON_ACCESSOR_PATH, NODE_INTERACTION_UNKNOWN_ASSIGNMENT, context));
7855
- }
7856
- }
7857
- };
7858
- /* CONSTRUCTOR */
7859
- const C = {
7860
- __proto__: null,
7861
- [ValueProperties]: IMPURE,
7862
- prototype: O
7863
- };
7864
- /* PURE CONSTRUCTOR */
7865
- const PC = {
7866
- __proto__: null,
7867
- [ValueProperties]: PURE,
7868
- prototype: O
7869
- };
7870
- const PC_WITH_ARRAY = {
7871
- __proto__: null,
7872
- [ValueProperties]: PURE_WITH_ARRAY,
7873
- prototype: O
7874
- };
7875
- const ARRAY_TYPE = {
7876
- __proto__: null,
7877
- [ValueProperties]: PURE,
7878
- from: O,
7879
- of: PF,
7880
- prototype: O
7881
- };
7882
- const INTL_MEMBER = {
7883
- __proto__: null,
7884
- [ValueProperties]: PURE,
7885
- supportedLocalesOf: PC
7886
- };
7887
- const knownGlobals = {
7888
- // Placeholders for global objects to avoid shape mutations
7889
- global: O,
7890
- globalThis: O,
7891
- self: O,
7892
- window: O,
7893
- // Common globals
7894
- __proto__: null,
7895
- [ValueProperties]: IMPURE,
7896
- Array: {
7897
- __proto__: null,
7898
- [ValueProperties]: IMPURE,
7899
- from: O,
7900
- isArray: PF,
7901
- of: PF,
7902
- prototype: O
7903
- },
7904
- ArrayBuffer: {
7905
- __proto__: null,
7906
- [ValueProperties]: PURE,
7907
- isView: PF,
7908
- prototype: O
7909
- },
7910
- Atomics: O,
7911
- BigInt: C,
7912
- BigInt64Array: C,
7913
- BigUint64Array: C,
7914
- Boolean: PC,
7915
- constructor: C,
7916
- DataView: PC,
7917
- Date: {
7918
- __proto__: null,
7919
- [ValueProperties]: PURE,
7920
- now: PF,
7921
- parse: PF,
7922
- prototype: O,
7923
- UTC: PF
7924
- },
7925
- decodeURI: PF,
7926
- decodeURIComponent: PF,
7927
- encodeURI: PF,
7928
- encodeURIComponent: PF,
7929
- Error: PC,
7930
- escape: PF,
7931
- eval: O,
7932
- EvalError: PC,
7933
- Float32Array: ARRAY_TYPE,
7934
- Float64Array: ARRAY_TYPE,
7935
- Function: C,
7936
- hasOwnProperty: O,
7937
- Infinity: O,
7938
- Int16Array: ARRAY_TYPE,
7939
- Int32Array: ARRAY_TYPE,
7940
- Int8Array: ARRAY_TYPE,
7941
- isFinite: PF,
7942
- isNaN: PF,
7943
- isPrototypeOf: O,
7944
- JSON: O,
7945
- Map: PC_WITH_ARRAY,
7946
- Math: {
7947
- __proto__: null,
7948
- [ValueProperties]: IMPURE,
7949
- abs: PF,
7950
- acos: PF,
7951
- acosh: PF,
7952
- asin: PF,
7953
- asinh: PF,
7954
- atan: PF,
7955
- atan2: PF,
7956
- atanh: PF,
7957
- cbrt: PF,
7958
- ceil: PF,
7959
- clz32: PF,
7960
- cos: PF,
7961
- cosh: PF,
7962
- exp: PF,
7963
- expm1: PF,
7964
- floor: PF,
7965
- fround: PF,
7966
- hypot: PF,
7967
- imul: PF,
7968
- log: PF,
7969
- log10: PF,
7970
- log1p: PF,
7971
- log2: PF,
7972
- max: PF,
7973
- min: PF,
7974
- pow: PF,
7975
- random: PF,
7976
- round: PF,
7977
- sign: PF,
7978
- sin: PF,
7979
- sinh: PF,
7980
- sqrt: PF,
7981
- tan: PF,
7982
- tanh: PF,
7983
- trunc: PF
7984
- },
7985
- NaN: O,
7986
- Number: {
7987
- __proto__: null,
7988
- [ValueProperties]: PURE,
7989
- isFinite: PF,
7990
- isInteger: PF,
7991
- isNaN: PF,
7992
- isSafeInteger: PF,
7993
- parseFloat: PF,
7994
- parseInt: PF,
7995
- prototype: O
7996
- },
7997
- Object: {
7998
- __proto__: null,
7999
- [ValueProperties]: PURE,
8000
- create: PF,
8001
- // Technically those can throw in certain situations, but we ignore this as
8002
- // code that relies on this will hopefully wrap this in a try-catch, which
8003
- // deoptimizes everything anyway
8004
- defineProperty: MUTATES_ARG_WITHOUT_ACCESSOR,
8005
- defineProperties: MUTATES_ARG_WITHOUT_ACCESSOR,
8006
- freeze: MUTATES_ARG_WITHOUT_ACCESSOR,
8007
- getOwnPropertyDescriptor: PF,
8008
- getOwnPropertyDescriptors: PF,
8009
- getOwnPropertyNames: PF,
8010
- getOwnPropertySymbols: PF,
8011
- getPrototypeOf: PF,
8012
- hasOwn: PF,
8013
- is: PF,
8014
- isExtensible: PF,
8015
- isFrozen: PF,
8016
- isSealed: PF,
8017
- keys: PF,
8018
- fromEntries: O,
8019
- entries: PF_NO_GETTER,
8020
- values: PF_NO_GETTER,
8021
- prototype: O
8022
- },
8023
- parseFloat: PF,
8024
- parseInt: PF,
8025
- Promise: {
8026
- __proto__: null,
8027
- [ValueProperties]: IMPURE,
8028
- all: O,
8029
- allSettled: O,
8030
- any: O,
8031
- prototype: O,
8032
- race: O,
8033
- reject: O,
8034
- resolve: O
8035
- },
8036
- propertyIsEnumerable: O,
8037
- Proxy: O,
8038
- RangeError: PC,
8039
- ReferenceError: PC,
8040
- Reflect: O,
8041
- RegExp: PC,
8042
- Set: PC_WITH_ARRAY,
8043
- SharedArrayBuffer: C,
8044
- String: {
8045
- __proto__: null,
8046
- [ValueProperties]: PURE,
8047
- fromCharCode: PF,
8048
- fromCodePoint: PF,
8049
- prototype: O,
8050
- raw: PF
8051
- },
8052
- Symbol: {
8053
- __proto__: null,
8054
- [ValueProperties]: PURE,
8055
- for: PF,
8056
- keyFor: PF,
8057
- prototype: O,
8058
- toStringTag: {
8059
- __proto__: null,
8060
- [ValueProperties]: {
8061
- deoptimizeArgumentsOnCall: doNothing,
8062
- getLiteralValue() {
8063
- return SymbolToStringTag;
8064
- },
8065
- hasEffectsWhenCalled: returnTrue
7258
+ };
7259
+ /* CONSTRUCTOR */
7260
+ const C = {
7261
+ __proto__: null,
7262
+ [ValueProperties]: IMPURE,
7263
+ prototype: O
7264
+ };
7265
+ /* PURE CONSTRUCTOR */
7266
+ const PC = {
7267
+ __proto__: null,
7268
+ [ValueProperties]: PURE,
7269
+ prototype: O
7270
+ };
7271
+ const PC_WITH_ARRAY = {
7272
+ __proto__: null,
7273
+ [ValueProperties]: PURE_WITH_ARRAY,
7274
+ prototype: O
7275
+ };
7276
+ const ARRAY_TYPE = {
7277
+ __proto__: null,
7278
+ [ValueProperties]: PURE,
7279
+ from: O,
7280
+ of: PF,
7281
+ prototype: O
7282
+ };
7283
+ const INTL_MEMBER = {
7284
+ __proto__: null,
7285
+ [ValueProperties]: PURE,
7286
+ supportedLocalesOf: PC
7287
+ };
7288
+ const knownGlobals = {
7289
+ // Placeholders for global objects to avoid shape mutations
7290
+ global: O,
7291
+ globalThis: O,
7292
+ self: O,
7293
+ window: O,
7294
+ // Common globals
7295
+ __proto__: null,
7296
+ [ValueProperties]: IMPURE,
7297
+ Array: {
7298
+ __proto__: null,
7299
+ [ValueProperties]: IMPURE,
7300
+ from: O,
7301
+ isArray: PF,
7302
+ of: PF,
7303
+ prototype: O
7304
+ },
7305
+ ArrayBuffer: {
7306
+ __proto__: null,
7307
+ [ValueProperties]: PURE,
7308
+ isView: PF,
7309
+ prototype: O
7310
+ },
7311
+ Atomics: O,
7312
+ BigInt: C,
7313
+ BigInt64Array: C,
7314
+ BigUint64Array: C,
7315
+ Boolean: PC,
7316
+ constructor: C,
7317
+ DataView: PC,
7318
+ Date: {
7319
+ __proto__: null,
7320
+ [ValueProperties]: PURE,
7321
+ now: PF,
7322
+ parse: PF,
7323
+ prototype: O,
7324
+ UTC: PF
7325
+ },
7326
+ decodeURI: PF,
7327
+ decodeURIComponent: PF,
7328
+ encodeURI: PF,
7329
+ encodeURIComponent: PF,
7330
+ Error: PC,
7331
+ escape: PF,
7332
+ eval: O,
7333
+ EvalError: PC,
7334
+ Float32Array: ARRAY_TYPE,
7335
+ Float64Array: ARRAY_TYPE,
7336
+ Function: C,
7337
+ hasOwnProperty: O,
7338
+ Infinity: O,
7339
+ Int16Array: ARRAY_TYPE,
7340
+ Int32Array: ARRAY_TYPE,
7341
+ Int8Array: ARRAY_TYPE,
7342
+ isFinite: PF,
7343
+ isNaN: PF,
7344
+ isPrototypeOf: O,
7345
+ JSON: O,
7346
+ Map: PC_WITH_ARRAY,
7347
+ Math: {
7348
+ __proto__: null,
7349
+ [ValueProperties]: IMPURE,
7350
+ abs: PF,
7351
+ acos: PF,
7352
+ acosh: PF,
7353
+ asin: PF,
7354
+ asinh: PF,
7355
+ atan: PF,
7356
+ atan2: PF,
7357
+ atanh: PF,
7358
+ cbrt: PF,
7359
+ ceil: PF,
7360
+ clz32: PF,
7361
+ cos: PF,
7362
+ cosh: PF,
7363
+ exp: PF,
7364
+ expm1: PF,
7365
+ floor: PF,
7366
+ fround: PF,
7367
+ hypot: PF,
7368
+ imul: PF,
7369
+ log: PF,
7370
+ log10: PF,
7371
+ log1p: PF,
7372
+ log2: PF,
7373
+ max: PF,
7374
+ min: PF,
7375
+ pow: PF,
7376
+ random: PF,
7377
+ round: PF,
7378
+ sign: PF,
7379
+ sin: PF,
7380
+ sinh: PF,
7381
+ sqrt: PF,
7382
+ tan: PF,
7383
+ tanh: PF,
7384
+ trunc: PF
7385
+ },
7386
+ NaN: O,
7387
+ Number: {
7388
+ __proto__: null,
7389
+ [ValueProperties]: PURE,
7390
+ isFinite: PF,
7391
+ isInteger: PF,
7392
+ isNaN: PF,
7393
+ isSafeInteger: PF,
7394
+ parseFloat: PF,
7395
+ parseInt: PF,
7396
+ prototype: O
7397
+ },
7398
+ Object: {
7399
+ __proto__: null,
7400
+ [ValueProperties]: PURE,
7401
+ create: PF,
7402
+ // Technically those can throw in certain situations, but we ignore this as
7403
+ // code that relies on this will hopefully wrap this in a try-catch, which
7404
+ // deoptimizes everything anyway
7405
+ defineProperty: MUTATES_ARG_WITHOUT_ACCESSOR,
7406
+ defineProperties: MUTATES_ARG_WITHOUT_ACCESSOR,
7407
+ freeze: MUTATES_ARG_WITHOUT_ACCESSOR,
7408
+ getOwnPropertyDescriptor: PF,
7409
+ getOwnPropertyDescriptors: PF,
7410
+ getOwnPropertyNames: PF,
7411
+ getOwnPropertySymbols: PF,
7412
+ getPrototypeOf: PF,
7413
+ hasOwn: PF,
7414
+ is: PF,
7415
+ isExtensible: PF,
7416
+ isFrozen: PF,
7417
+ isSealed: PF,
7418
+ keys: PF,
7419
+ fromEntries: O,
7420
+ entries: PF_NO_GETTER,
7421
+ values: PF_NO_GETTER,
7422
+ prototype: O
7423
+ },
7424
+ parseFloat: PF,
7425
+ parseInt: PF,
7426
+ Promise: {
7427
+ __proto__: null,
7428
+ [ValueProperties]: IMPURE,
7429
+ all: O,
7430
+ allSettled: O,
7431
+ any: O,
7432
+ prototype: O,
7433
+ race: O,
7434
+ reject: O,
7435
+ resolve: O
7436
+ },
7437
+ propertyIsEnumerable: O,
7438
+ Proxy: O,
7439
+ RangeError: PC,
7440
+ ReferenceError: PC,
7441
+ Reflect: O,
7442
+ RegExp: PC,
7443
+ Set: PC_WITH_ARRAY,
7444
+ SharedArrayBuffer: C,
7445
+ String: {
7446
+ __proto__: null,
7447
+ [ValueProperties]: PURE,
7448
+ fromCharCode: PF,
7449
+ fromCodePoint: PF,
7450
+ prototype: O,
7451
+ raw: PF
7452
+ },
7453
+ Symbol: {
7454
+ __proto__: null,
7455
+ [ValueProperties]: PURE,
7456
+ for: PF,
7457
+ keyFor: PF,
7458
+ prototype: O,
7459
+ toStringTag: {
7460
+ __proto__: null,
7461
+ [ValueProperties]: {
7462
+ deoptimizeArgumentsOnCall: doNothing,
7463
+ getLiteralValue() {
7464
+ return SymbolToStringTag;
7465
+ },
7466
+ hasEffectsWhenCalled: returnTrue
8066
7467
  }
8067
7468
  }
8068
7469
  },
@@ -8729,295 +8130,928 @@ const knownGlobals = {
8729
8130
  for (const global of ['window', 'global', 'self', 'globalThis']) {
8730
8131
  knownGlobals[global] = knownGlobals;
8731
8132
  }
8732
- function getGlobalAtPath(path) {
8733
- let currentGlobal = knownGlobals;
8734
- for (const pathSegment of path) {
8735
- if (typeof pathSegment !== 'string') {
8736
- return null;
8133
+ function getGlobalAtPath(path) {
8134
+ let currentGlobal = knownGlobals;
8135
+ for (const pathSegment of path) {
8136
+ if (typeof pathSegment !== 'string') {
8137
+ return null;
8138
+ }
8139
+ currentGlobal = currentGlobal[pathSegment];
8140
+ if (!currentGlobal) {
8141
+ return null;
8142
+ }
8143
+ }
8144
+ return currentGlobal[ValueProperties];
8145
+ }
8146
+
8147
+ class GlobalVariable extends Variable {
8148
+ constructor(name) {
8149
+ super(name);
8150
+ // Ensure we use live-bindings for globals as we do not know if they have
8151
+ // been reassigned
8152
+ this.markReassigned();
8153
+ }
8154
+ deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker) {
8155
+ switch (interaction.type) {
8156
+ // While there is no point in testing these cases as at the moment, they
8157
+ // are also covered via other means, we keep them for completeness
8158
+ case INTERACTION_ACCESSED:
8159
+ case INTERACTION_ASSIGNED: {
8160
+ if (!getGlobalAtPath([this.name, ...path].slice(0, -1))) {
8161
+ super.deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker);
8162
+ }
8163
+ return;
8164
+ }
8165
+ case INTERACTION_CALLED: {
8166
+ const globalAtPath = getGlobalAtPath([this.name, ...path]);
8167
+ if (globalAtPath) {
8168
+ globalAtPath.deoptimizeArgumentsOnCall(interaction);
8169
+ }
8170
+ else {
8171
+ super.deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker);
8172
+ }
8173
+ return;
8174
+ }
8175
+ }
8176
+ }
8177
+ getLiteralValueAtPath(path, _recursionTracker, _origin) {
8178
+ const globalAtPath = getGlobalAtPath([this.name, ...path]);
8179
+ return globalAtPath ? globalAtPath.getLiteralValue() : UnknownValue;
8180
+ }
8181
+ hasEffectsOnInteractionAtPath(path, interaction, context) {
8182
+ switch (interaction.type) {
8183
+ case INTERACTION_ACCESSED: {
8184
+ if (path.length === 0) {
8185
+ // Technically, "undefined" is a global variable of sorts
8186
+ return this.name !== 'undefined' && !getGlobalAtPath([this.name]);
8187
+ }
8188
+ return !getGlobalAtPath([this.name, ...path].slice(0, -1));
8189
+ }
8190
+ case INTERACTION_ASSIGNED: {
8191
+ return true;
8192
+ }
8193
+ case INTERACTION_CALLED: {
8194
+ const globalAtPath = getGlobalAtPath([this.name, ...path]);
8195
+ return !globalAtPath || globalAtPath.hasEffectsWhenCalled(interaction, context);
8196
+ }
8197
+ }
8198
+ }
8199
+ }
8200
+
8201
+ class LocalVariable extends Variable {
8202
+ constructor(name, declarator, init, context, kind) {
8203
+ super(name);
8204
+ this.init = init;
8205
+ this.calledFromTryStatement = false;
8206
+ this.additionalInitializers = null;
8207
+ this.expressionsToBeDeoptimized = [];
8208
+ this.declarations = declarator ? [declarator] : [];
8209
+ this.deoptimizationTracker = context.deoptimizationTracker;
8210
+ this.module = context.module;
8211
+ this.kind = kind;
8212
+ }
8213
+ addDeclaration(identifier, init) {
8214
+ this.declarations.push(identifier);
8215
+ this.markInitializersForDeoptimization().push(init);
8216
+ }
8217
+ consolidateInitializers() {
8218
+ if (this.additionalInitializers) {
8219
+ for (const initializer of this.additionalInitializers) {
8220
+ initializer.deoptimizePath(UNKNOWN_PATH);
8221
+ }
8222
+ this.additionalInitializers = null;
8223
+ }
8224
+ }
8225
+ deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker) {
8226
+ if (this.isReassigned) {
8227
+ deoptimizeInteraction(interaction);
8228
+ return;
8229
+ }
8230
+ recursionTracker.withTrackedEntityAtPath(path, this.init, () => this.init.deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker), undefined);
8231
+ }
8232
+ deoptimizePath(path) {
8233
+ if (this.isReassigned ||
8234
+ this.deoptimizationTracker.trackEntityAtPathAndGetIfTracked(path, this)) {
8235
+ return;
8236
+ }
8237
+ if (path.length === 0) {
8238
+ this.markReassigned();
8239
+ const expressionsToBeDeoptimized = this.expressionsToBeDeoptimized;
8240
+ this.expressionsToBeDeoptimized = parseAst_js.EMPTY_ARRAY;
8241
+ for (const expression of expressionsToBeDeoptimized) {
8242
+ expression.deoptimizeCache();
8243
+ }
8244
+ this.init.deoptimizePath(UNKNOWN_PATH);
8245
+ }
8246
+ else {
8247
+ this.init.deoptimizePath(path);
8248
+ }
8249
+ }
8250
+ getLiteralValueAtPath(path, recursionTracker, origin) {
8251
+ if (this.isReassigned) {
8252
+ return UnknownValue;
8253
+ }
8254
+ return recursionTracker.withTrackedEntityAtPath(path, this.init, () => {
8255
+ this.expressionsToBeDeoptimized.push(origin);
8256
+ return this.init.getLiteralValueAtPath(path, recursionTracker, origin);
8257
+ }, UnknownValue);
8258
+ }
8259
+ getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin) {
8260
+ if (this.isReassigned) {
8261
+ return UNKNOWN_RETURN_EXPRESSION;
8262
+ }
8263
+ return recursionTracker.withTrackedEntityAtPath(path, this.init, () => {
8264
+ this.expressionsToBeDeoptimized.push(origin);
8265
+ return this.init.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin);
8266
+ }, UNKNOWN_RETURN_EXPRESSION);
8267
+ }
8268
+ hasEffectsOnInteractionAtPath(path, interaction, context) {
8269
+ switch (interaction.type) {
8270
+ case INTERACTION_ACCESSED: {
8271
+ if (this.isReassigned)
8272
+ return true;
8273
+ return (!context.accessed.trackEntityAtPathAndGetIfTracked(path, this) &&
8274
+ this.init.hasEffectsOnInteractionAtPath(path, interaction, context));
8275
+ }
8276
+ case INTERACTION_ASSIGNED: {
8277
+ if (this.included)
8278
+ return true;
8279
+ if (path.length === 0)
8280
+ return false;
8281
+ if (this.isReassigned)
8282
+ return true;
8283
+ return (!context.assigned.trackEntityAtPathAndGetIfTracked(path, this) &&
8284
+ this.init.hasEffectsOnInteractionAtPath(path, interaction, context));
8285
+ }
8286
+ case INTERACTION_CALLED: {
8287
+ if (this.isReassigned)
8288
+ return true;
8289
+ return (!(interaction.withNew ? context.instantiated : context.called).trackEntityAtPathAndGetIfTracked(path, interaction.args, this) &&
8290
+ this.init.hasEffectsOnInteractionAtPath(path, interaction, context));
8291
+ }
8292
+ }
8293
+ }
8294
+ include() {
8295
+ if (!this.included) {
8296
+ super.include();
8297
+ for (const declaration of this.declarations) {
8298
+ // If node is a default export, it can save a tree-shaking run to include the full declaration now
8299
+ if (!declaration.included)
8300
+ declaration.include(createInclusionContext(), false);
8301
+ let node = declaration.parent;
8302
+ while (!node.included) {
8303
+ // We do not want to properly include parents in case they are part of a dead branch
8304
+ // in which case .include() might pull in more dead code
8305
+ node.included = true;
8306
+ if (node.type === parseAst_js.Program)
8307
+ break;
8308
+ node = node.parent;
8309
+ }
8310
+ }
8311
+ }
8312
+ }
8313
+ includeCallArguments(context, parameters) {
8314
+ if (this.isReassigned || context.includedCallArguments.has(this.init)) {
8315
+ for (const argument of parameters) {
8316
+ argument.include(context, false);
8317
+ }
8318
+ }
8319
+ else {
8320
+ context.includedCallArguments.add(this.init);
8321
+ this.init.includeCallArguments(context, parameters);
8322
+ context.includedCallArguments.delete(this.init);
8323
+ }
8324
+ }
8325
+ markCalledFromTryStatement() {
8326
+ this.calledFromTryStatement = true;
8327
+ }
8328
+ markInitializersForDeoptimization() {
8329
+ if (this.additionalInitializers === null) {
8330
+ this.additionalInitializers = [this.init];
8331
+ this.init = UNKNOWN_EXPRESSION;
8332
+ this.markReassigned();
8333
+ }
8334
+ return this.additionalInitializers;
8335
+ }
8336
+ }
8337
+
8338
+ const tdzVariableKinds = new Set(['class', 'const', 'let', 'var', 'using', 'await using']);
8339
+ class Identifier extends NodeBase {
8340
+ constructor() {
8341
+ super(...arguments);
8342
+ this.variable = null;
8343
+ this.isReferenceVariable = false;
8344
+ }
8345
+ get isTDZAccess() {
8346
+ if (!isFlagSet(this.flags, 4 /* Flag.tdzAccessDefined */)) {
8347
+ return null;
8348
+ }
8349
+ return isFlagSet(this.flags, 8 /* Flag.tdzAccess */);
8350
+ }
8351
+ set isTDZAccess(value) {
8352
+ this.flags = setFlag(this.flags, 4 /* Flag.tdzAccessDefined */, true);
8353
+ this.flags = setFlag(this.flags, 8 /* Flag.tdzAccess */, value);
8354
+ }
8355
+ addExportedVariables(variables, exportNamesByVariable) {
8356
+ if (exportNamesByVariable.has(this.variable)) {
8357
+ variables.push(this.variable);
8358
+ }
8359
+ }
8360
+ bind() {
8361
+ if (!this.variable && is_reference(this, this.parent)) {
8362
+ this.variable = this.scope.findVariable(this.name);
8363
+ this.variable.addReference(this);
8364
+ this.isReferenceVariable = true;
8365
+ }
8366
+ }
8367
+ declare(kind, init) {
8368
+ let variable;
8369
+ const { treeshake } = this.scope.context.options;
8370
+ switch (kind) {
8371
+ case 'var': {
8372
+ variable = this.scope.addDeclaration(this, this.scope.context, init, kind);
8373
+ if (treeshake && treeshake.correctVarValueBeforeDeclaration) {
8374
+ // Necessary to make sure the init is deoptimized. We cannot call deoptimizePath here.
8375
+ variable.markInitializersForDeoptimization();
8376
+ }
8377
+ break;
8378
+ }
8379
+ case 'function': {
8380
+ // in strict mode, functions are only hoisted within a scope but not across block scopes
8381
+ variable = this.scope.addDeclaration(this, this.scope.context, init, kind);
8382
+ break;
8383
+ }
8384
+ case 'let':
8385
+ case 'const':
8386
+ case 'using':
8387
+ case 'await using':
8388
+ case 'class': {
8389
+ variable = this.scope.addDeclaration(this, this.scope.context, init, kind);
8390
+ break;
8391
+ }
8392
+ case 'parameter': {
8393
+ variable = this.scope.addParameterDeclaration(this);
8394
+ break;
8395
+ }
8396
+ /* istanbul ignore next */
8397
+ default: {
8398
+ /* istanbul ignore next */
8399
+ throw new Error(`Internal Error: Unexpected identifier kind ${kind}.`);
8400
+ }
8401
+ }
8402
+ return [(this.variable = variable)];
8403
+ }
8404
+ deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker) {
8405
+ this.variable.deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker);
8406
+ }
8407
+ deoptimizePath(path) {
8408
+ if (path.length === 0 && !this.scope.contains(this.name)) {
8409
+ this.disallowImportReassignment();
8410
+ }
8411
+ // We keep conditional chaining because an unknown Node could have an
8412
+ // Identifier as property that might be deoptimized by default
8413
+ this.variable?.deoptimizePath(path);
8414
+ }
8415
+ getLiteralValueAtPath(path, recursionTracker, origin) {
8416
+ return this.getVariableRespectingTDZ().getLiteralValueAtPath(path, recursionTracker, origin);
8417
+ }
8418
+ getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin) {
8419
+ const [expression, isPure] = this.getVariableRespectingTDZ().getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin);
8420
+ return [expression, isPure || this.isPureFunction(path)];
8421
+ }
8422
+ hasEffects(context) {
8423
+ if (!this.deoptimized)
8424
+ this.applyDeoptimizations();
8425
+ if (this.isPossibleTDZ() && this.variable.kind !== 'var') {
8426
+ return true;
8427
+ }
8428
+ return (this.scope.context.options.treeshake
8429
+ .unknownGlobalSideEffects &&
8430
+ this.variable instanceof GlobalVariable &&
8431
+ !this.isPureFunction(EMPTY_PATH) &&
8432
+ this.variable.hasEffectsOnInteractionAtPath(EMPTY_PATH, NODE_INTERACTION_UNKNOWN_ACCESS, context));
8433
+ }
8434
+ hasEffectsOnInteractionAtPath(path, interaction, context) {
8435
+ switch (interaction.type) {
8436
+ case INTERACTION_ACCESSED: {
8437
+ return (this.variable !== null &&
8438
+ !this.isPureFunction(path) &&
8439
+ this.getVariableRespectingTDZ().hasEffectsOnInteractionAtPath(path, interaction, context));
8440
+ }
8441
+ case INTERACTION_ASSIGNED: {
8442
+ return (path.length > 0 ? this.getVariableRespectingTDZ() : this.variable).hasEffectsOnInteractionAtPath(path, interaction, context);
8443
+ }
8444
+ case INTERACTION_CALLED: {
8445
+ return (!this.isPureFunction(path) &&
8446
+ this.getVariableRespectingTDZ().hasEffectsOnInteractionAtPath(path, interaction, context));
8447
+ }
8448
+ }
8449
+ }
8450
+ include() {
8451
+ if (!this.deoptimized)
8452
+ this.applyDeoptimizations();
8453
+ if (!this.included) {
8454
+ this.included = true;
8455
+ if (this.variable !== null) {
8456
+ this.scope.context.includeVariableInModule(this.variable);
8457
+ }
8458
+ }
8459
+ }
8460
+ includeCallArguments(context, parameters) {
8461
+ this.variable.includeCallArguments(context, parameters);
8462
+ }
8463
+ isPossibleTDZ() {
8464
+ // return cached value to avoid issues with the next tree-shaking pass
8465
+ const cachedTdzAccess = this.isTDZAccess;
8466
+ if (cachedTdzAccess !== null)
8467
+ return cachedTdzAccess;
8468
+ if (!(this.variable instanceof LocalVariable &&
8469
+ this.variable.kind &&
8470
+ tdzVariableKinds.has(this.variable.kind) &&
8471
+ // we ignore possible TDZs due to circular module dependencies as
8472
+ // otherwise we get many false positives
8473
+ this.variable.module === this.scope.context.module)) {
8474
+ return (this.isTDZAccess = false);
8475
+ }
8476
+ let decl_id;
8477
+ if (this.variable.declarations &&
8478
+ this.variable.declarations.length === 1 &&
8479
+ (decl_id = this.variable.declarations[0]) &&
8480
+ this.start < decl_id.start &&
8481
+ closestParentFunctionOrProgram(this) === closestParentFunctionOrProgram(decl_id)) {
8482
+ // a variable accessed before its declaration
8483
+ // in the same function or at top level of module
8484
+ return (this.isTDZAccess = true);
8485
+ }
8486
+ // We ignore the case where the module is not yet executed because
8487
+ // moduleSideEffects are false.
8488
+ if (!this.variable.initReached && this.scope.context.module.isExecuted) {
8489
+ // Either a const/let TDZ violation or
8490
+ // var use before declaration was encountered.
8491
+ return (this.isTDZAccess = true);
8492
+ }
8493
+ return (this.isTDZAccess = false);
8494
+ }
8495
+ markDeclarationReached() {
8496
+ this.variable.initReached = true;
8497
+ }
8498
+ render(code, { snippets: { getPropertyAccess }, useOriginalName }, { renderedParentType, isCalleeOfRenderedParent, isShorthandProperty } = parseAst_js.BLANK) {
8499
+ if (this.variable) {
8500
+ const name = this.variable.getName(getPropertyAccess, useOriginalName);
8501
+ if (name !== this.name) {
8502
+ code.overwrite(this.start, this.end, name, {
8503
+ contentOnly: true,
8504
+ storeName: true
8505
+ });
8506
+ if (isShorthandProperty) {
8507
+ code.prependRight(this.start, `${this.name}: `);
8508
+ }
8509
+ }
8510
+ // In strict mode, any variable named "eval" must be the actual "eval" function
8511
+ if (name === 'eval' &&
8512
+ renderedParentType === parseAst_js.CallExpression &&
8513
+ isCalleeOfRenderedParent) {
8514
+ code.appendRight(this.start, '0, ');
8515
+ }
8516
+ }
8517
+ }
8518
+ disallowImportReassignment() {
8519
+ return this.scope.context.error(parseAst_js.logIllegalImportReassignment(this.name, this.scope.context.module.id), this.start);
8520
+ }
8521
+ applyDeoptimizations() {
8522
+ this.deoptimized = true;
8523
+ if (this.variable instanceof LocalVariable) {
8524
+ this.variable.consolidateInitializers();
8525
+ this.scope.context.requestTreeshakingPass();
8526
+ }
8527
+ if (this.isReferenceVariable) {
8528
+ this.variable.addUsedPlace(this);
8529
+ this.scope.context.requestTreeshakingPass();
8530
+ }
8531
+ }
8532
+ getVariableRespectingTDZ() {
8533
+ if (this.isPossibleTDZ()) {
8534
+ return UNKNOWN_EXPRESSION;
8535
+ }
8536
+ return this.variable;
8537
+ }
8538
+ isPureFunction(path) {
8539
+ let currentPureFunction = this.scope.context.manualPureFunctions[this.name];
8540
+ for (const segment of path) {
8541
+ if (currentPureFunction) {
8542
+ if (currentPureFunction[PureFunctionKey]) {
8543
+ return true;
8544
+ }
8545
+ currentPureFunction = currentPureFunction[segment];
8546
+ }
8547
+ else {
8548
+ return false;
8549
+ }
8550
+ }
8551
+ return currentPureFunction?.[PureFunctionKey];
8552
+ }
8553
+ }
8554
+ function closestParentFunctionOrProgram(node) {
8555
+ while (node && !/^Program|Function/.test(node.type)) {
8556
+ node = node.parent;
8557
+ }
8558
+ // one of: ArrowFunctionExpression, FunctionDeclaration, FunctionExpression or Program
8559
+ return node;
8560
+ }
8561
+
8562
+ const MAX_TRACKED_INTERACTIONS = 20;
8563
+ const NO_INTERACTIONS = parseAst_js.EMPTY_ARRAY;
8564
+ const UNKNOWN_DEOPTIMIZED_FIELD = new Set([UnknownKey]);
8565
+ const EMPTY_PATH_TRACKER = new PathTracker();
8566
+ const UNKNOWN_DEOPTIMIZED_ENTITY = new Set([UNKNOWN_EXPRESSION]);
8567
+ class ParameterVariable extends LocalVariable {
8568
+ constructor(name, declarator, context) {
8569
+ super(name, declarator, UNKNOWN_EXPRESSION, context, 'parameter');
8570
+ this.deoptimizationInteractions = [];
8571
+ this.deoptimizations = new PathTracker();
8572
+ this.deoptimizedFields = new Set();
8573
+ this.entitiesToBeDeoptimized = new Set();
8574
+ this.expressionsUseTheKnownValue = [];
8575
+ this.knownValue = null;
8576
+ this.knownValueLiteral = UnknownValue;
8577
+ this.frozenValue = null;
8578
+ }
8579
+ addEntityToBeDeoptimized(entity) {
8580
+ if (entity === UNKNOWN_EXPRESSION) {
8581
+ // As unknown expressions fully deoptimize all interactions, we can clear
8582
+ // the interaction cache at this point provided we keep this optimization
8583
+ // in mind when adding new interactions
8584
+ if (!this.entitiesToBeDeoptimized.has(UNKNOWN_EXPRESSION)) {
8585
+ this.entitiesToBeDeoptimized.add(UNKNOWN_EXPRESSION);
8586
+ for (const { interaction } of this.deoptimizationInteractions) {
8587
+ deoptimizeInteraction(interaction);
8588
+ }
8589
+ this.deoptimizationInteractions = NO_INTERACTIONS;
8590
+ }
8591
+ }
8592
+ else if (this.deoptimizedFields.has(UnknownKey)) {
8593
+ // This means that we already deoptimized all interactions and no longer
8594
+ // track them
8595
+ entity.deoptimizePath(UNKNOWN_PATH);
8596
+ }
8597
+ else if (!this.entitiesToBeDeoptimized.has(entity)) {
8598
+ this.entitiesToBeDeoptimized.add(entity);
8599
+ for (const field of this.deoptimizedFields) {
8600
+ entity.deoptimizePath([field]);
8601
+ }
8602
+ for (const { interaction, path } of this.deoptimizationInteractions) {
8603
+ entity.deoptimizeArgumentsOnInteractionAtPath(interaction, path, SHARED_RECURSION_TRACKER);
8604
+ }
8605
+ }
8606
+ }
8607
+ markReassigned() {
8608
+ if (this.isReassigned) {
8609
+ return;
8610
+ }
8611
+ super.markReassigned();
8612
+ for (const expression of this.expressionsUseTheKnownValue) {
8613
+ expression.deoptimizeCache();
8614
+ }
8615
+ this.expressionsUseTheKnownValue = parseAst_js.EMPTY_ARRAY;
8616
+ }
8617
+ deoptimizeCache() {
8618
+ this.markReassigned();
8619
+ }
8620
+ /**
8621
+ * Update the known value of the parameter variable.
8622
+ * Must be called for every function call, so it can track all the arguments,
8623
+ * and deoptimizeCache itself to mark reassigned if the argument is changed.
8624
+ * @param argument The argument of the function call
8625
+ */
8626
+ updateKnownValue(argument) {
8627
+ if (this.isReassigned) {
8628
+ return;
8629
+ }
8630
+ if (this.knownValue === null) {
8631
+ this.knownValue = argument;
8632
+ this.knownValueLiteral = argument.getLiteralValueAtPath(EMPTY_PATH, SHARED_RECURSION_TRACKER, this);
8633
+ return;
8634
+ }
8635
+ // the same literal or identifier, do nothing
8636
+ if (this.knownValue === argument ||
8637
+ (this.knownValue instanceof Identifier &&
8638
+ argument instanceof Identifier &&
8639
+ this.knownValue.variable === argument.variable)) {
8640
+ return;
8641
+ }
8642
+ const oldValue = this.knownValueLiteral;
8643
+ if (typeof oldValue === 'symbol') {
8644
+ this.markReassigned();
8645
+ return;
8646
+ }
8647
+ // add tracking for the new argument
8648
+ const newValue = argument.getLiteralValueAtPath(EMPTY_PATH, SHARED_RECURSION_TRACKER, this);
8649
+ if (newValue !== oldValue) {
8650
+ this.markReassigned();
8651
+ }
8652
+ }
8653
+ /**
8654
+ * This function freezes the known value of the parameter variable,
8655
+ * so the optimization starts with a certain ExpressionEntity.
8656
+ * The optimization can be undone by calling `markReassigned`.
8657
+ * @returns the frozen value
8658
+ */
8659
+ getKnownValue() {
8660
+ if (this.frozenValue === null) {
8661
+ this.frozenValue = this.knownValue || UNKNOWN_EXPRESSION;
8662
+ }
8663
+ return this.frozenValue;
8664
+ }
8665
+ getLiteralValueAtPath(path, recursionTracker, origin) {
8666
+ if (this.isReassigned) {
8667
+ return UnknownValue;
8668
+ }
8669
+ const knownValue = this.getKnownValue();
8670
+ this.expressionsUseTheKnownValue.push(origin);
8671
+ return recursionTracker.withTrackedEntityAtPath(path, knownValue, () => knownValue.getLiteralValueAtPath(path, recursionTracker, origin), UnknownValue);
8672
+ }
8673
+ hasEffectsOnInteractionAtPath(path, interaction, context) {
8674
+ if (this.isReassigned || interaction.type === INTERACTION_ASSIGNED) {
8675
+ return super.hasEffectsOnInteractionAtPath(path, interaction, context);
8676
+ }
8677
+ const knownValue = this.getKnownValue();
8678
+ return knownValue.hasEffectsOnInteractionAtPath(path, interaction, context);
8679
+ }
8680
+ deoptimizeArgumentsOnInteractionAtPath(interaction, path) {
8681
+ // For performance reasons, we fully deoptimize all deeper interactions
8682
+ if (path.length >= 2 ||
8683
+ this.entitiesToBeDeoptimized.has(UNKNOWN_EXPRESSION) ||
8684
+ this.deoptimizationInteractions.length >= MAX_TRACKED_INTERACTIONS ||
8685
+ (path.length === 1 &&
8686
+ (this.deoptimizedFields.has(UnknownKey) ||
8687
+ (interaction.type === INTERACTION_CALLED && this.deoptimizedFields.has(path[0]))))) {
8688
+ deoptimizeInteraction(interaction);
8689
+ return;
8690
+ }
8691
+ if (!this.deoptimizations.trackEntityAtPathAndGetIfTracked(path, interaction.args)) {
8692
+ for (const entity of this.entitiesToBeDeoptimized) {
8693
+ entity.deoptimizeArgumentsOnInteractionAtPath(interaction, path, SHARED_RECURSION_TRACKER);
8694
+ }
8695
+ if (!this.entitiesToBeDeoptimized.has(UNKNOWN_EXPRESSION)) {
8696
+ this.deoptimizationInteractions.push({
8697
+ interaction,
8698
+ path
8699
+ });
8700
+ }
8701
+ }
8702
+ }
8703
+ deoptimizePath(path) {
8704
+ if (path.length === 0) {
8705
+ this.markReassigned();
8706
+ return;
8707
+ }
8708
+ if (this.deoptimizedFields.has(UnknownKey)) {
8709
+ return;
8710
+ }
8711
+ const key = path[0];
8712
+ if (this.deoptimizedFields.has(key)) {
8713
+ return;
8714
+ }
8715
+ this.deoptimizedFields.add(key);
8716
+ for (const entity of this.entitiesToBeDeoptimized) {
8717
+ // We do not need a recursion tracker here as we already track whether
8718
+ // this field is deoptimized
8719
+ entity.deoptimizePath([key]);
8720
+ }
8721
+ if (key === UnknownKey) {
8722
+ // save some memory
8723
+ this.deoptimizationInteractions = NO_INTERACTIONS;
8724
+ this.deoptimizations = EMPTY_PATH_TRACKER;
8725
+ this.deoptimizedFields = UNKNOWN_DEOPTIMIZED_FIELD;
8726
+ this.entitiesToBeDeoptimized = UNKNOWN_DEOPTIMIZED_ENTITY;
8727
+ }
8728
+ }
8729
+ getReturnExpressionWhenCalledAtPath(path) {
8730
+ // We deoptimize everything that is called as that will trivially deoptimize
8731
+ // the corresponding return expressions as well and avoid badly performing
8732
+ // and complicated alternatives
8733
+ if (path.length === 0) {
8734
+ this.deoptimizePath(UNKNOWN_PATH);
8735
+ }
8736
+ else if (!this.deoptimizedFields.has(path[0])) {
8737
+ this.deoptimizePath([path[0]]);
8738
+ }
8739
+ return UNKNOWN_RETURN_EXPRESSION;
8740
+ }
8741
+ }
8742
+
8743
+ function getSafeName(baseName, usedNames, forbiddenNames) {
8744
+ let safeName = baseName;
8745
+ let count = 1;
8746
+ while (usedNames.has(safeName) || RESERVED_NAMES.has(safeName) || forbiddenNames?.has(safeName)) {
8747
+ safeName = `${baseName}$${toBase64(count++)}`;
8748
+ }
8749
+ usedNames.add(safeName);
8750
+ return safeName;
8751
+ }
8752
+
8753
+ class Scope {
8754
+ constructor() {
8755
+ this.children = [];
8756
+ this.variables = new Map();
8757
+ }
8758
+ /*
8759
+ Redeclaration rules:
8760
+ - var can redeclare var
8761
+ - in function scopes, function and var can redeclare function and var
8762
+ - var is hoisted across scopes, function remains in the scope it is declared
8763
+ - var and function can redeclare function parameters, but parameters cannot redeclare parameters
8764
+ - function cannot redeclare catch scope parameters
8765
+ - var can redeclare catch scope parameters in a way
8766
+ - if the parameter is an identifier and not a pattern
8767
+ - then the variable is still declared in the hoisted outer scope, but the initializer is assigned to the parameter
8768
+ - const, let, class, and function except in the cases above cannot redeclare anything
8769
+ */
8770
+ addDeclaration(identifier, context, init, kind) {
8771
+ const name = identifier.name;
8772
+ const existingVariable = this.hoistedVariables?.get(name) || this.variables.get(name);
8773
+ if (existingVariable) {
8774
+ const existingKind = existingVariable.kind;
8775
+ if (kind === 'var' && existingKind === 'var') {
8776
+ existingVariable.addDeclaration(identifier, init);
8777
+ return existingVariable;
8778
+ }
8779
+ context.error(parseAst_js.logRedeclarationError(name), identifier.start);
8780
+ }
8781
+ const newVariable = new LocalVariable(identifier.name, identifier, init, context, kind);
8782
+ this.variables.set(name, newVariable);
8783
+ return newVariable;
8784
+ }
8785
+ addHoistedVariable(name, variable) {
8786
+ (this.hoistedVariables ||= new Map()).set(name, variable);
8787
+ }
8788
+ contains(name) {
8789
+ return this.variables.has(name);
8790
+ }
8791
+ findVariable(_name) {
8792
+ /* istanbul ignore next */
8793
+ throw new Error('Internal Error: findVariable needs to be implemented by a subclass');
8794
+ }
8795
+ }
8796
+
8797
+ class ChildScope extends Scope {
8798
+ constructor(parent, context) {
8799
+ super();
8800
+ this.parent = parent;
8801
+ this.context = context;
8802
+ this.accessedOutsideVariables = new Map();
8803
+ parent.children.push(this);
8804
+ }
8805
+ addAccessedDynamicImport(importExpression) {
8806
+ (this.accessedDynamicImports || (this.accessedDynamicImports = new Set())).add(importExpression);
8807
+ if (this.parent instanceof ChildScope) {
8808
+ this.parent.addAccessedDynamicImport(importExpression);
8737
8809
  }
8738
- currentGlobal = currentGlobal[pathSegment];
8739
- if (!currentGlobal) {
8740
- return null;
8810
+ }
8811
+ addAccessedGlobals(globals, accessedGlobalsByScope) {
8812
+ const accessedGlobals = accessedGlobalsByScope.get(this) || new Set();
8813
+ for (const name of globals) {
8814
+ accessedGlobals.add(name);
8815
+ }
8816
+ accessedGlobalsByScope.set(this, accessedGlobals);
8817
+ if (this.parent instanceof ChildScope) {
8818
+ this.parent.addAccessedGlobals(globals, accessedGlobalsByScope);
8741
8819
  }
8742
8820
  }
8743
- return currentGlobal[ValueProperties];
8744
- }
8745
-
8746
- class GlobalVariable extends Variable {
8747
- constructor(name) {
8748
- super(name);
8749
- // Ensure we use live-bindings for globals as we do not know if they have
8750
- // been reassigned
8751
- this.markReassigned();
8821
+ addNamespaceMemberAccess(name, variable) {
8822
+ this.accessedOutsideVariables.set(name, variable);
8823
+ this.parent.addNamespaceMemberAccess(name, variable);
8752
8824
  }
8753
- deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker) {
8754
- switch (interaction.type) {
8755
- // While there is no point in testing these cases as at the moment, they
8756
- // are also covered via other means, we keep them for completeness
8757
- case INTERACTION_ACCESSED:
8758
- case INTERACTION_ASSIGNED: {
8759
- if (!getGlobalAtPath([this.name, ...path].slice(0, -1))) {
8760
- super.deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker);
8825
+ addReturnExpression(expression) {
8826
+ this.parent instanceof ChildScope && this.parent.addReturnExpression(expression);
8827
+ }
8828
+ addUsedOutsideNames(usedNames, format, exportNamesByVariable, accessedGlobalsByScope) {
8829
+ for (const variable of this.accessedOutsideVariables.values()) {
8830
+ if (variable.included) {
8831
+ usedNames.add(variable.getBaseVariableName());
8832
+ if (format === 'system' && exportNamesByVariable.has(variable)) {
8833
+ usedNames.add('exports');
8761
8834
  }
8762
- return;
8763
8835
  }
8764
- case INTERACTION_CALLED: {
8765
- const globalAtPath = getGlobalAtPath([this.name, ...path]);
8766
- if (globalAtPath) {
8767
- globalAtPath.deoptimizeArgumentsOnCall(interaction);
8768
- }
8769
- else {
8770
- super.deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker);
8771
- }
8772
- return;
8836
+ }
8837
+ const accessedGlobals = accessedGlobalsByScope.get(this);
8838
+ if (accessedGlobals) {
8839
+ for (const name of accessedGlobals) {
8840
+ usedNames.add(name);
8773
8841
  }
8774
8842
  }
8775
8843
  }
8776
- getLiteralValueAtPath(path, _recursionTracker, _origin) {
8777
- const globalAtPath = getGlobalAtPath([this.name, ...path]);
8778
- return globalAtPath ? globalAtPath.getLiteralValue() : UnknownValue;
8844
+ contains(name) {
8845
+ return this.variables.has(name) || this.parent.contains(name);
8779
8846
  }
8780
- hasEffectsOnInteractionAtPath(path, interaction, context) {
8781
- switch (interaction.type) {
8782
- case INTERACTION_ACCESSED: {
8783
- if (path.length === 0) {
8784
- // Technically, "undefined" is a global variable of sorts
8785
- return this.name !== 'undefined' && !getGlobalAtPath([this.name]);
8847
+ deconflict(format, exportNamesByVariable, accessedGlobalsByScope) {
8848
+ const usedNames = new Set();
8849
+ this.addUsedOutsideNames(usedNames, format, exportNamesByVariable, accessedGlobalsByScope);
8850
+ if (this.accessedDynamicImports) {
8851
+ for (const importExpression of this.accessedDynamicImports) {
8852
+ if (importExpression.inlineNamespace) {
8853
+ usedNames.add(importExpression.inlineNamespace.getBaseVariableName());
8786
8854
  }
8787
- return !getGlobalAtPath([this.name, ...path].slice(0, -1));
8788
- }
8789
- case INTERACTION_ASSIGNED: {
8790
- return true;
8791
8855
  }
8792
- case INTERACTION_CALLED: {
8793
- const globalAtPath = getGlobalAtPath([this.name, ...path]);
8794
- return !globalAtPath || globalAtPath.hasEffectsWhenCalled(interaction, context);
8856
+ }
8857
+ for (const [name, variable] of this.variables) {
8858
+ if (variable.included || variable.alwaysRendered) {
8859
+ variable.setRenderNames(null, getSafeName(name, usedNames, variable.forbiddenNames));
8795
8860
  }
8796
8861
  }
8797
- }
8798
- }
8799
-
8800
- const tdzVariableKinds = new Set(['class', 'const', 'let', 'var', 'using', 'await using']);
8801
- class Identifier extends NodeBase {
8802
- constructor() {
8803
- super(...arguments);
8804
- this.variable = null;
8805
- this.isReferenceVariable = false;
8806
- }
8807
- get isTDZAccess() {
8808
- if (!isFlagSet(this.flags, 4 /* Flag.tdzAccessDefined */)) {
8809
- return null;
8862
+ for (const scope of this.children) {
8863
+ scope.deconflict(format, exportNamesByVariable, accessedGlobalsByScope);
8810
8864
  }
8811
- return isFlagSet(this.flags, 8 /* Flag.tdzAccess */);
8812
8865
  }
8813
- set isTDZAccess(value) {
8814
- this.flags = setFlag(this.flags, 4 /* Flag.tdzAccessDefined */, true);
8815
- this.flags = setFlag(this.flags, 8 /* Flag.tdzAccess */, value);
8866
+ findLexicalBoundary() {
8867
+ return this.parent.findLexicalBoundary();
8816
8868
  }
8817
- addExportedVariables(variables, exportNamesByVariable) {
8818
- if (exportNamesByVariable.has(this.variable)) {
8819
- variables.push(this.variable);
8869
+ findVariable(name) {
8870
+ const knownVariable = this.variables.get(name) || this.accessedOutsideVariables.get(name);
8871
+ if (knownVariable) {
8872
+ return knownVariable;
8820
8873
  }
8874
+ const variable = this.parent.findVariable(name);
8875
+ this.accessedOutsideVariables.set(name, variable);
8876
+ return variable;
8821
8877
  }
8822
- bind() {
8823
- if (!this.variable && is_reference(this, this.parent)) {
8824
- this.variable = this.scope.findVariable(this.name);
8825
- this.variable.addReference(this);
8826
- this.isReferenceVariable = true;
8827
- }
8878
+ }
8879
+
8880
+ class CatchBodyScope extends ChildScope {
8881
+ constructor(parent) {
8882
+ super(parent, parent.context);
8883
+ this.parent = parent;
8828
8884
  }
8829
- declare(kind, init) {
8830
- let variable;
8831
- const { treeshake } = this.scope.context.options;
8832
- switch (kind) {
8833
- case 'var': {
8834
- variable = this.scope.addDeclaration(this, this.scope.context, init, kind);
8835
- if (treeshake && treeshake.correctVarValueBeforeDeclaration) {
8836
- // Necessary to make sure the init is deoptimized. We cannot call deoptimizePath here.
8837
- variable.markInitializersForDeoptimization();
8885
+ addDeclaration(identifier, context, init, kind) {
8886
+ if (kind === 'var') {
8887
+ const name = identifier.name;
8888
+ const existingVariable = this.hoistedVariables?.get(name) || this.variables.get(name);
8889
+ if (existingVariable) {
8890
+ const existingKind = existingVariable.kind;
8891
+ if (existingKind === 'parameter' &&
8892
+ // If this is a destructured parameter, it is forbidden to redeclare
8893
+ existingVariable.declarations[0].parent.type === parseAst_js.CatchClause) {
8894
+ // If this is a var with the same name as the catch scope parameter,
8895
+ // the assignment actually goes to the parameter and the var is
8896
+ // hoisted without assignment. Locally, it is shadowed by the
8897
+ // parameter
8898
+ const declaredVariable = this.parent.parent.addDeclaration(identifier, context, UNDEFINED_EXPRESSION, kind);
8899
+ // To avoid the need to rewrite the declaration, we link the variable
8900
+ // names. If we ever implement a logic that splits initialization and
8901
+ // assignment for hoisted vars, the "renderLikeHoisted" logic can be
8902
+ // removed again.
8903
+ // We do not need to check whether there already is a linked
8904
+ // variable because then declaredVariable would be that linked
8905
+ // variable.
8906
+ existingVariable.renderLikeHoisted(declaredVariable);
8907
+ this.addHoistedVariable(name, declaredVariable);
8908
+ return declaredVariable;
8838
8909
  }
8839
- break;
8840
- }
8841
- case 'function': {
8842
- // in strict mode, functions are only hoisted within a scope but not across block scopes
8843
- variable = this.scope.addDeclaration(this, this.scope.context, init, kind);
8844
- break;
8845
- }
8846
- case 'let':
8847
- case 'const':
8848
- case 'using':
8849
- case 'await using':
8850
- case 'class': {
8851
- variable = this.scope.addDeclaration(this, this.scope.context, init, kind);
8852
- break;
8853
- }
8854
- case 'parameter': {
8855
- variable = this.scope.addParameterDeclaration(this);
8856
- break;
8857
- }
8858
- /* istanbul ignore next */
8859
- default: {
8860
- /* istanbul ignore next */
8861
- throw new Error(`Internal Error: Unexpected identifier kind ${kind}.`);
8910
+ if (existingKind === 'var') {
8911
+ existingVariable.addDeclaration(identifier, init);
8912
+ return existingVariable;
8913
+ }
8914
+ return context.error(parseAst_js.logRedeclarationError(name), identifier.start);
8862
8915
  }
8916
+ // We only add parameters to parameter scopes
8917
+ const declaredVariable = this.parent.parent.addDeclaration(identifier, context, init, kind);
8918
+ // Necessary to make sure the init is deoptimized for conditional declarations.
8919
+ // We cannot call deoptimizePath here.
8920
+ declaredVariable.markInitializersForDeoptimization();
8921
+ // We add the variable to this and all parent scopes to reliably detect conflicts
8922
+ this.addHoistedVariable(name, declaredVariable);
8923
+ return declaredVariable;
8863
8924
  }
8864
- return [(this.variable = variable)];
8925
+ return super.addDeclaration(identifier, context, init, kind);
8865
8926
  }
8866
- deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker) {
8867
- this.variable.deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker);
8927
+ }
8928
+
8929
+ class FunctionBodyScope extends ChildScope {
8930
+ constructor(parent) {
8931
+ super(parent, parent.context);
8868
8932
  }
8869
- deoptimizePath(path) {
8870
- if (path.length === 0 && !this.scope.contains(this.name)) {
8871
- this.disallowImportReassignment();
8933
+ // There is stuff that is only allowed in function scopes, i.e. functions can
8934
+ // be redeclared, functions and var can redeclare each other
8935
+ addDeclaration(identifier, context, init, kind) {
8936
+ const name = identifier.name;
8937
+ const existingVariable = this.hoistedVariables?.get(name) || this.variables.get(name);
8938
+ if (existingVariable) {
8939
+ const existingKind = existingVariable.kind;
8940
+ if ((kind === 'var' || kind === 'function') &&
8941
+ (existingKind === 'var' || existingKind === 'function' || existingKind === 'parameter')) {
8942
+ existingVariable.addDeclaration(identifier, init);
8943
+ return existingVariable;
8944
+ }
8945
+ context.error(parseAst_js.logRedeclarationError(name), identifier.start);
8872
8946
  }
8873
- // We keep conditional chaining because an unknown Node could have an
8874
- // Identifier as property that might be deoptimized by default
8875
- this.variable?.deoptimizePath(path);
8876
- }
8877
- getLiteralValueAtPath(path, recursionTracker, origin) {
8878
- return this.getVariableRespectingTDZ().getLiteralValueAtPath(path, recursionTracker, origin);
8879
- }
8880
- getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin) {
8881
- const [expression, isPure] = this.getVariableRespectingTDZ().getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin);
8882
- return [expression, isPure || this.isPureFunction(path)];
8947
+ const newVariable = new LocalVariable(identifier.name, identifier, init, context, kind);
8948
+ this.variables.set(name, newVariable);
8949
+ return newVariable;
8883
8950
  }
8884
- hasEffects(context) {
8885
- if (!this.deoptimized)
8886
- this.applyDeoptimizations();
8887
- if (this.isPossibleTDZ() && this.variable.kind !== 'var') {
8888
- return true;
8889
- }
8890
- return (this.scope.context.options.treeshake
8891
- .unknownGlobalSideEffects &&
8892
- this.variable instanceof GlobalVariable &&
8893
- !this.isPureFunction(EMPTY_PATH) &&
8894
- this.variable.hasEffectsOnInteractionAtPath(EMPTY_PATH, NODE_INTERACTION_UNKNOWN_ACCESS, context));
8951
+ }
8952
+
8953
+ class ParameterScope extends ChildScope {
8954
+ constructor(parent, isCatchScope) {
8955
+ super(parent, parent.context);
8956
+ this.parameters = [];
8957
+ this.hasRest = false;
8958
+ this.bodyScope = isCatchScope ? new CatchBodyScope(this) : new FunctionBodyScope(this);
8895
8959
  }
8896
- hasEffectsOnInteractionAtPath(path, interaction, context) {
8897
- switch (interaction.type) {
8898
- case INTERACTION_ACCESSED: {
8899
- return (this.variable !== null &&
8900
- !this.isPureFunction(path) &&
8901
- this.getVariableRespectingTDZ().hasEffectsOnInteractionAtPath(path, interaction, context));
8902
- }
8903
- case INTERACTION_ASSIGNED: {
8904
- return (path.length > 0 ? this.getVariableRespectingTDZ() : this.variable).hasEffectsOnInteractionAtPath(path, interaction, context);
8905
- }
8906
- case INTERACTION_CALLED: {
8907
- return (!this.isPureFunction(path) &&
8908
- this.getVariableRespectingTDZ().hasEffectsOnInteractionAtPath(path, interaction, context));
8909
- }
8960
+ /**
8961
+ * Adds a parameter to this scope. Parameters must be added in the correct
8962
+ * order, i.e. from left to right.
8963
+ */
8964
+ addParameterDeclaration(identifier) {
8965
+ const { name, start } = identifier;
8966
+ const existingParameter = this.variables.get(name);
8967
+ if (existingParameter) {
8968
+ return this.context.error(parseAst_js.logDuplicateArgumentNameError(name), start);
8910
8969
  }
8970
+ const variable = new ParameterVariable(name, identifier, this.context);
8971
+ this.variables.set(name, variable);
8972
+ // We also add it to the body scope to detect name conflicts with local
8973
+ // variables. We still need the intermediate scope, though, as parameter
8974
+ // defaults are NOT taken from the body scope but from the parameters or
8975
+ // outside scope.
8976
+ this.bodyScope.addHoistedVariable(name, variable);
8977
+ return variable;
8911
8978
  }
8912
- include() {
8913
- if (!this.deoptimized)
8914
- this.applyDeoptimizations();
8915
- if (!this.included) {
8916
- this.included = true;
8917
- if (this.variable !== null) {
8918
- this.scope.context.includeVariableInModule(this.variable);
8979
+ addParameterVariables(parameters, hasRest) {
8980
+ this.parameters = parameters;
8981
+ for (const parameterList of parameters) {
8982
+ for (const parameter of parameterList) {
8983
+ parameter.alwaysRendered = true;
8919
8984
  }
8920
8985
  }
8986
+ this.hasRest = hasRest;
8921
8987
  }
8922
8988
  includeCallArguments(context, parameters) {
8923
- this.variable.includeCallArguments(context, parameters);
8924
- }
8925
- isPossibleTDZ() {
8926
- // return cached value to avoid issues with the next tree-shaking pass
8927
- const cachedTdzAccess = this.isTDZAccess;
8928
- if (cachedTdzAccess !== null)
8929
- return cachedTdzAccess;
8930
- if (!(this.variable instanceof LocalVariable &&
8931
- this.variable.kind &&
8932
- tdzVariableKinds.has(this.variable.kind) &&
8933
- // we ignore possible TDZs due to circular module dependencies as
8934
- // otherwise we get many false positives
8935
- this.variable.module === this.scope.context.module)) {
8936
- return (this.isTDZAccess = false);
8937
- }
8938
- let decl_id;
8939
- if (this.variable.declarations &&
8940
- this.variable.declarations.length === 1 &&
8941
- (decl_id = this.variable.declarations[0]) &&
8942
- this.start < decl_id.start &&
8943
- closestParentFunctionOrProgram(this) === closestParentFunctionOrProgram(decl_id)) {
8944
- // a variable accessed before its declaration
8945
- // in the same function or at top level of module
8946
- return (this.isTDZAccess = true);
8947
- }
8948
- // We ignore the case where the module is not yet executed because
8949
- // moduleSideEffects are false.
8950
- if (!this.variable.initReached && this.scope.context.module.isExecuted) {
8951
- // Either a const/let TDZ violation or
8952
- // var use before declaration was encountered.
8953
- return (this.isTDZAccess = true);
8989
+ let calledFromTryStatement = false;
8990
+ let argumentIncluded = false;
8991
+ const restParameter = this.hasRest && this.parameters[this.parameters.length - 1];
8992
+ for (const checkedArgument of parameters) {
8993
+ if (checkedArgument instanceof SpreadElement) {
8994
+ for (const argument of parameters) {
8995
+ argument.include(context, false);
8996
+ }
8997
+ break;
8998
+ }
8954
8999
  }
8955
- return (this.isTDZAccess = false);
8956
- }
8957
- markDeclarationReached() {
8958
- this.variable.initReached = true;
8959
- }
8960
- render(code, { snippets: { getPropertyAccess }, useOriginalName }, { renderedParentType, isCalleeOfRenderedParent, isShorthandProperty } = parseAst_js.BLANK) {
8961
- if (this.variable) {
8962
- const name = this.variable.getName(getPropertyAccess, useOriginalName);
8963
- if (name !== this.name) {
8964
- code.overwrite(this.start, this.end, name, {
8965
- contentOnly: true,
8966
- storeName: true
8967
- });
8968
- if (isShorthandProperty) {
8969
- code.prependRight(this.start, `${this.name}: `);
9000
+ for (let index = parameters.length - 1; index >= 0; index--) {
9001
+ const parameterVariables = this.parameters[index] || restParameter;
9002
+ const argument = parameters[index];
9003
+ if (parameterVariables) {
9004
+ calledFromTryStatement = false;
9005
+ if (parameterVariables.length === 0) {
9006
+ // handle empty destructuring
9007
+ argumentIncluded = true;
9008
+ }
9009
+ else {
9010
+ for (const variable of parameterVariables) {
9011
+ if (variable.included) {
9012
+ argumentIncluded = true;
9013
+ }
9014
+ if (variable.calledFromTryStatement) {
9015
+ calledFromTryStatement = true;
9016
+ }
9017
+ }
8970
9018
  }
8971
9019
  }
8972
- // In strict mode, any variable named "eval" must be the actual "eval" function
8973
- if (name === 'eval' &&
8974
- renderedParentType === parseAst_js.CallExpression &&
8975
- isCalleeOfRenderedParent) {
8976
- code.appendRight(this.start, '0, ');
9020
+ if (!argumentIncluded && argument.shouldBeIncluded(context)) {
9021
+ argumentIncluded = true;
9022
+ }
9023
+ if (argumentIncluded) {
9024
+ argument.include(context, calledFromTryStatement);
8977
9025
  }
8978
9026
  }
8979
9027
  }
8980
- disallowImportReassignment() {
8981
- return this.scope.context.error(parseAst_js.logIllegalImportReassignment(this.name, this.scope.context.module.id), this.start);
9028
+ }
9029
+
9030
+ class ReturnValueScope extends ParameterScope {
9031
+ constructor() {
9032
+ super(...arguments);
9033
+ this.returnExpression = null;
9034
+ this.returnExpressions = [];
8982
9035
  }
8983
- applyDeoptimizations() {
8984
- this.deoptimized = true;
8985
- if (this.variable instanceof LocalVariable) {
8986
- this.variable.consolidateInitializers();
8987
- this.scope.context.requestTreeshakingPass();
8988
- }
8989
- if (this.isReferenceVariable) {
8990
- this.variable.addUsedPlace(this);
8991
- }
9036
+ addReturnExpression(expression) {
9037
+ this.returnExpressions.push(expression);
8992
9038
  }
8993
- getVariableRespectingTDZ() {
8994
- if (this.isPossibleTDZ()) {
8995
- return UNKNOWN_EXPRESSION;
8996
- }
8997
- return this.variable;
9039
+ getReturnExpression() {
9040
+ if (this.returnExpression === null)
9041
+ this.updateReturnExpression();
9042
+ return this.returnExpression;
8998
9043
  }
8999
- isPureFunction(path) {
9000
- let currentPureFunction = this.scope.context.manualPureFunctions[this.name];
9001
- for (const segment of path) {
9002
- if (currentPureFunction) {
9003
- if (currentPureFunction[PureFunctionKey]) {
9004
- return true;
9005
- }
9006
- currentPureFunction = currentPureFunction[segment];
9007
- }
9008
- else {
9009
- return false;
9044
+ updateReturnExpression() {
9045
+ if (this.returnExpressions.length === 1) {
9046
+ this.returnExpression = this.returnExpressions[0];
9047
+ }
9048
+ else {
9049
+ this.returnExpression = UNKNOWN_EXPRESSION;
9050
+ for (const expression of this.returnExpressions) {
9051
+ expression.deoptimizePath(UNKNOWN_PATH);
9010
9052
  }
9011
9053
  }
9012
- return currentPureFunction?.[PureFunctionKey];
9013
- }
9014
- }
9015
- function closestParentFunctionOrProgram(node) {
9016
- while (node && !/^Program|Function/.test(node.type)) {
9017
- node = node.parent;
9018
9054
  }
9019
- // one of: ArrowFunctionExpression, FunctionDeclaration, FunctionExpression or Program
9020
- return node;
9021
9055
  }
9022
9056
 
9023
9057
  function treeshakeNode(node, code, start, end) {
@@ -9308,17 +9342,11 @@ class RestElement extends NodeBase {
9308
9342
  }
9309
9343
  }
9310
9344
 
9311
- // This handler does nothing.
9312
- // Since we always re-evaluate argument values in a new tree-shaking pass,
9313
- // we don't need to get notified if it is deoptimized.
9314
- const EMPTY_DEOPTIMIZABLE_HANDLER = { deoptimizeCache() { } };
9315
9345
  class FunctionBase extends NodeBase {
9316
9346
  constructor() {
9317
9347
  super(...arguments);
9318
- this.knownParameterValues = [];
9319
- this.allArguments = [];
9320
9348
  this.objectEntity = null;
9321
- this.functionParametersOptimized = false;
9349
+ this.parameterVariableValuesDeoptimized = false;
9322
9350
  }
9323
9351
  get async() {
9324
9352
  return isFlagSet(this.flags, 256 /* Flag.async */);
@@ -9338,84 +9366,22 @@ class FunctionBase extends NodeBase {
9338
9366
  set generator(value) {
9339
9367
  this.flags = setFlag(this.flags, 4194304 /* Flag.generator */, value);
9340
9368
  }
9341
- /**
9342
- * update knownParameterValues when a call is made to this function
9343
- * @param newArguments arguments of the call
9344
- */
9345
- updateKnownParameterValues(newArguments) {
9369
+ updateParameterVariableValues(_arguments) {
9346
9370
  for (let position = 0; position < this.params.length; position++) {
9347
- // only the "this" argument newArguments[0] can be null
9348
- // it's possible that some arguments are empty, so the value is undefined
9349
- const argument = newArguments[position + 1] ?? UNDEFINED_EXPRESSION;
9350
9371
  const parameter = this.params[position];
9351
- // RestElement can be, and can only be, the last parameter
9352
- if (parameter instanceof RestElement) {
9353
- return;
9354
- }
9355
- const knownParameterValue = this.knownParameterValues[position];
9356
- if (knownParameterValue === undefined) {
9357
- this.knownParameterValues[position] = argument;
9358
- continue;
9359
- }
9360
- if (knownParameterValue === UNKNOWN_EXPRESSION ||
9361
- knownParameterValue === argument ||
9362
- (knownParameterValue instanceof Identifier &&
9363
- argument instanceof Identifier &&
9364
- knownParameterValue.variable === argument.variable)) {
9372
+ if (!(parameter instanceof Identifier)) {
9365
9373
  continue;
9366
9374
  }
9367
- const oldValue = knownParameterValue.getLiteralValueAtPath(EMPTY_PATH, SHARED_RECURSION_TRACKER, EMPTY_DEOPTIMIZABLE_HANDLER);
9368
- const newValue = argument.getLiteralValueAtPath(EMPTY_PATH, SHARED_RECURSION_TRACKER, EMPTY_DEOPTIMIZABLE_HANDLER);
9369
- if (oldValue !== newValue || typeof oldValue === 'symbol') {
9370
- this.knownParameterValues[position] = UNKNOWN_EXPRESSION;
9371
- } // else both are the same literal, no need to update
9372
- }
9373
- }
9374
- forwardArgumentsForFunctionCalledOnce(newArguments) {
9375
- for (let position = 0; position < this.params.length; position++) {
9376
- const parameter = this.params[position];
9377
- if (parameter instanceof Identifier) {
9378
- const ParameterVariable = parameter.variable;
9379
- const argument = newArguments[position + 1] ?? UNDEFINED_EXPRESSION;
9380
- ParameterVariable?.setKnownValue(argument);
9381
- }
9382
- }
9383
- }
9384
- /**
9385
- * each time tree-shake starts, this method should be called to reoptimize the parameters
9386
- * a parameter's state will change at most twice:
9387
- * `undefined` (no call is made) -> an expression -> `UnknownArgument`
9388
- * we are sure it will converge, and can use state from last iteration
9389
- */
9390
- applyFunctionParameterOptimization() {
9391
- if (this.allArguments.length === 0) {
9392
- return;
9393
- }
9394
- if (this.allArguments.length === 1) {
9395
- // we are sure what knownParameterValues will be, so skip it and do setKnownValue
9396
- this.forwardArgumentsForFunctionCalledOnce(this.allArguments[0]);
9397
- return;
9398
- }
9399
- // reoptimize all arguments, that's why we save them
9400
- for (const argumentsList of this.allArguments) {
9401
- this.updateKnownParameterValues(argumentsList);
9402
- }
9403
- for (let position = 0; position < this.params.length; position++) {
9404
- const parameter = this.params[position];
9405
- // Parameters without default values
9406
- if (parameter instanceof Identifier) {
9407
- const parameterVariable = parameter.variable;
9408
- // Only the RestElement may be undefined
9409
- const knownParameterValue = this.knownParameterValues[position];
9410
- parameterVariable?.setKnownValue(knownParameterValue);
9411
- }
9375
+ const parameterVariable = parameter.variable;
9376
+ const argument = _arguments[position + 1] ?? UNDEFINED_EXPRESSION;
9377
+ parameterVariable.updateKnownValue(argument);
9412
9378
  }
9413
9379
  }
9414
- deoptimizeFunctionParameters() {
9380
+ deoptimizeParameterVariableValues() {
9415
9381
  for (const parameter of this.params) {
9416
9382
  if (parameter instanceof Identifier) {
9417
9383
  const parameterVariable = parameter.variable;
9418
- parameterVariable?.markReassigned();
9384
+ parameterVariable.markReassigned();
9419
9385
  }
9420
9386
  }
9421
9387
  }
@@ -9443,7 +9409,7 @@ class FunctionBase extends NodeBase {
9443
9409
  this.addArgumentToBeDeoptimized(argument);
9444
9410
  }
9445
9411
  }
9446
- this.allArguments.push(args);
9412
+ this.updateParameterVariableValues(args);
9447
9413
  }
9448
9414
  else {
9449
9415
  this.getObjectEntity().deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker);
@@ -9518,14 +9484,10 @@ class FunctionBase extends NodeBase {
9518
9484
  return variable?.getOnlyFunctionCallUsed() ?? false;
9519
9485
  }
9520
9486
  include(context, includeChildrenRecursively) {
9521
- const shouldOptimizeFunctionParameters = this.onlyFunctionCallUsed();
9522
- if (shouldOptimizeFunctionParameters) {
9523
- this.applyFunctionParameterOptimization();
9524
- }
9525
- else if (this.functionParametersOptimized) {
9526
- this.deoptimizeFunctionParameters();
9487
+ if (!this.parameterVariableValuesDeoptimized && !this.onlyFunctionCallUsed()) {
9488
+ this.parameterVariableValuesDeoptimized = true;
9489
+ this.deoptimizeParameterVariableValues();
9527
9490
  }
9528
- this.functionParametersOptimized = shouldOptimizeFunctionParameters;
9529
9491
  if (!this.deoptimized)
9530
9492
  this.applyDeoptimizations();
9531
9493
  this.included = true;
@@ -10280,7 +10242,7 @@ class MemberExpression extends NodeBase {
10280
10242
  }
10281
10243
  deoptimizeCache() {
10282
10244
  const { expressionsToBeDeoptimized, object } = this;
10283
- this.expressionsToBeDeoptimized = [];
10245
+ this.expressionsToBeDeoptimized = parseAst_js.EMPTY_ARRAY;
10284
10246
  this.propertyKey = UnknownKey;
10285
10247
  object.deoptimizePath(UNKNOWN_PATH);
10286
10248
  for (const expression of expressionsToBeDeoptimized) {
@@ -10431,6 +10393,7 @@ class MemberExpression extends NodeBase {
10431
10393
  }
10432
10394
  if (this.variable) {
10433
10395
  this.variable.addUsedPlace(this);
10396
+ this.scope.context.requestTreeshakingPass();
10434
10397
  }
10435
10398
  }
10436
10399
  applyAssignmentDeoptimization() {
@@ -10630,21 +10593,17 @@ class CallExpression extends CallExpressionBase {
10630
10593
  };
10631
10594
  }
10632
10595
  hasEffects(context) {
10633
- try {
10634
- for (const argument of this.arguments) {
10635
- if (argument.hasEffects(context))
10636
- return true;
10637
- }
10638
- if (this.annotationPure) {
10639
- return false;
10640
- }
10641
- return (this.callee.hasEffects(context) ||
10642
- this.callee.hasEffectsOnInteractionAtPath(EMPTY_PATH, this.interaction, context));
10596
+ if (!this.deoptimized)
10597
+ this.applyDeoptimizations();
10598
+ for (const argument of this.arguments) {
10599
+ if (argument.hasEffects(context))
10600
+ return true;
10643
10601
  }
10644
- finally {
10645
- if (!this.deoptimized)
10646
- this.applyDeoptimizations();
10602
+ if (this.annotationPure) {
10603
+ return false;
10647
10604
  }
10605
+ return (this.callee.hasEffects(context) ||
10606
+ this.callee.hasEffectsOnInteractionAtPath(EMPTY_PATH, this.interaction, context));
10648
10607
  }
10649
10608
  include(context, includeChildrenRecursively) {
10650
10609
  if (!this.deoptimized)
@@ -11081,24 +11040,15 @@ class ConditionalExpression extends NodeBase {
11081
11040
  this.alternate.deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker);
11082
11041
  }
11083
11042
  deoptimizeCache() {
11084
- if (this.usedBranch ||
11085
- this.isBranchResolutionAnalysed ||
11086
- this.expressionsToBeDeoptimized.length > 0) {
11087
- // Request another pass because we need to ensure "include" runs again if it is rendered
11088
- this.scope.context.requestTreeshakingPass();
11089
- }
11090
- const { expressionsToBeDeoptimized } = this;
11091
- if (expressionsToBeDeoptimized.length > 0) {
11092
- this.expressionsToBeDeoptimized = [];
11093
- for (const expression of expressionsToBeDeoptimized) {
11094
- expression.deoptimizeCache();
11095
- }
11096
- }
11097
- this.isBranchResolutionAnalysed = false;
11098
11043
  if (this.usedBranch !== null) {
11099
11044
  const unusedBranch = this.usedBranch === this.consequent ? this.alternate : this.consequent;
11100
11045
  this.usedBranch = null;
11101
11046
  unusedBranch.deoptimizePath(UNKNOWN_PATH);
11047
+ const { expressionsToBeDeoptimized } = this;
11048
+ this.expressionsToBeDeoptimized = parseAst_js.EMPTY_ARRAY;
11049
+ for (const expression of expressionsToBeDeoptimized) {
11050
+ expression.deoptimizeCache();
11051
+ }
11102
11052
  }
11103
11053
  }
11104
11054
  deoptimizePath(path) {
@@ -11112,10 +11062,10 @@ class ConditionalExpression extends NodeBase {
11112
11062
  }
11113
11063
  }
11114
11064
  getLiteralValueAtPath(path, recursionTracker, origin) {
11115
- this.expressionsToBeDeoptimized.push(origin);
11116
11065
  const usedBranch = this.getUsedBranch();
11117
11066
  if (!usedBranch)
11118
11067
  return UnknownValue;
11068
+ this.expressionsToBeDeoptimized.push(origin);
11119
11069
  return usedBranch.getLiteralValueAtPath(path, recursionTracker, origin);
11120
11070
  }
11121
11071
  getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin) {
@@ -11612,7 +11562,7 @@ class IfStatement extends NodeBase {
11612
11562
  this.testValue = unset;
11613
11563
  }
11614
11564
  deoptimizeCache() {
11615
- this.testValue = unset;
11565
+ this.testValue = UnknownValue;
11616
11566
  }
11617
11567
  hasEffects(context) {
11618
11568
  if (this.test.hasEffects(context)) {
@@ -12420,24 +12370,18 @@ class LogicalExpression extends NodeBase {
12420
12370
  this.right.deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker);
12421
12371
  }
12422
12372
  deoptimizeCache() {
12423
- if (this.usedBranch ||
12424
- this.isBranchResolutionAnalysed ||
12425
- this.expressionsToBeDeoptimized.length > 0) {
12426
- // Request another pass because we need to ensure "include" runs again if it is rendered
12427
- this.scope.context.requestTreeshakingPass();
12428
- }
12429
- const { expressionsToBeDeoptimized } = this;
12430
- if (expressionsToBeDeoptimized.length > 0) {
12431
- this.expressionsToBeDeoptimized = [];
12432
- for (const expression of expressionsToBeDeoptimized) {
12433
- expression.deoptimizeCache();
12434
- }
12435
- }
12436
- this.isBranchResolutionAnalysed = false;
12437
12373
  if (this.usedBranch) {
12438
12374
  const unusedBranch = this.usedBranch === this.left ? this.right : this.left;
12439
12375
  this.usedBranch = null;
12440
12376
  unusedBranch.deoptimizePath(UNKNOWN_PATH);
12377
+ const { scope: { context }, expressionsToBeDeoptimized } = this;
12378
+ this.expressionsToBeDeoptimized = parseAst_js.EMPTY_ARRAY;
12379
+ for (const expression of expressionsToBeDeoptimized) {
12380
+ expression.deoptimizeCache();
12381
+ }
12382
+ // Request another pass because we need to ensure "include" runs again if
12383
+ // it is rendered
12384
+ context.requestTreeshakingPass();
12441
12385
  }
12442
12386
  }
12443
12387
  deoptimizePath(path) {
@@ -12451,10 +12395,10 @@ class LogicalExpression extends NodeBase {
12451
12395
  }
12452
12396
  }
12453
12397
  getLiteralValueAtPath(path, recursionTracker, origin) {
12454
- this.expressionsToBeDeoptimized.push(origin);
12455
12398
  const usedBranch = this.getUsedBranch();
12456
12399
  if (!usedBranch)
12457
12400
  return UnknownValue;
12401
+ this.expressionsToBeDeoptimized.push(origin);
12458
12402
  return usedBranch.getLiteralValueAtPath(path, recursionTracker, origin);
12459
12403
  }
12460
12404
  getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin) {