Skip to content

Commit 7fb50f9

Browse files
authored
Call includeNode for self or children nodes in includeDestructuredIfNecessary (#6090)
* Add test * Call includeNode for self or children nodes in includeDestructuredIfNecessary * Replace includeDestructuredIfNecessary with a stub in MemberExpression
1 parent 235dc74 commit 7fb50f9

File tree

9 files changed

+56
-54
lines changed

9 files changed

+56
-54
lines changed

src/ast/nodes/ArrayPattern.ts

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -86,24 +86,19 @@ export default class ArrayPattern extends NodeBase implements DeclarationPattern
8686
): boolean {
8787
let included = false;
8888
const includedPatternPath = getIncludedPatternPath(destructuredInitPath);
89-
for (const element of this.elements) {
89+
for (const element of [...this.elements].reverse()) {
9090
if (element) {
91-
element.included ||= included;
91+
if (included && !element.included) {
92+
element.includeNode(context);
93+
}
9294
included =
9395
element.includeDestructuredIfNecessary(context, includedPatternPath, init) || included;
9496
}
9597
}
96-
if (included) {
97-
// This is necessary so that if any pattern element is included, all are
98-
// included for proper deconflicting
99-
for (const element of this.elements) {
100-
if (element && !element.included) {
101-
element.included = true;
102-
element.includeDestructuredIfNecessary(context, includedPatternPath, init);
103-
}
104-
}
98+
if (!this.included && included) {
99+
this.includeNode(context);
105100
}
106-
return (this.included ||= included);
101+
return this.included;
107102
}
108103

109104
markDeclarationReached(): void {

src/ast/nodes/AssignmentPattern.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,16 @@ export default class AssignmentPattern extends NodeBase implements DeclarationPa
7171
if ((included ||= this.right.shouldBeIncluded(context))) {
7272
this.right.include(context, false);
7373
if (!this.left.included) {
74-
this.left.included = true;
74+
this.left.includeNode(context);
7575
// Unfortunately, we need to include the left side again now, so that
7676
// any declared variables are properly included.
7777
this.left.includeDestructuredIfNecessary(context, destructuredInitPath, init);
7878
}
7979
}
80-
return (this.included = included);
80+
if (!this.included && included) {
81+
this.includeNode(context);
82+
}
83+
return this.included;
8184
}
8285

8386
includeNode(context: InclusionContext) {

src/ast/nodes/Identifier.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,9 @@ export default class Identifier extends IdentifierBase implements DeclarationPat
115115
}
116116
const { propertyReadSideEffects } = this.scope.context.options
117117
.treeshake as NormalizedTreeshakingOptions;
118+
let included = this.included;
118119
if (
119-
(this.included ||=
120+
(included ||=
120121
destructuredInitPath.length > 0 &&
121122
!context.brokenFlow &&
122123
propertyReadSideEffects &&
@@ -131,9 +132,11 @@ export default class Identifier extends IdentifierBase implements DeclarationPat
131132
this.scope.context.includeVariableInModule(this.variable, EMPTY_PATH, context);
132133
}
133134
init.includePath(destructuredInitPath, context);
134-
return true;
135135
}
136-
return false;
136+
if (!this.included && included) {
137+
this.includeNode(context);
138+
}
139+
return this.included;
137140
}
138141

139142
markDeclarationReached(): void {

src/ast/nodes/MemberExpression.ts

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { logIllegalImportReassignment, logMissingExport } from '../../utils/logs
77
import type { NodeRenderOptions, RenderOptions } from '../../utils/renderHelpers';
88
import type { DeoptimizableEntity } from '../DeoptimizableEntity';
99
import type { HasEffectsContext, InclusionContext } from '../ExecutionContext';
10-
import { createHasEffectsContext, createInclusionContext } from '../ExecutionContext';
10+
import { createInclusionContext } from '../ExecutionContext';
1111
import type {
1212
NodeInteraction,
1313
NodeInteractionAccessed,
@@ -440,25 +440,14 @@ export default class MemberExpression
440440
}
441441
}
442442

443-
includeDestructuredIfNecessary(
444-
context: InclusionContext,
445-
destructuredInitPath: ObjectPath,
446-
init: ExpressionEntity
447-
): boolean {
448-
if (
449-
(this.included ||=
450-
destructuredInitPath.length > 0 &&
451-
!context.brokenFlow &&
452-
init.hasEffectsOnInteractionAtPath(
453-
destructuredInitPath,
454-
NODE_INTERACTION_UNKNOWN_ACCESS,
455-
createHasEffectsContext()
456-
))
457-
) {
458-
init.include(context, false);
459-
return true;
460-
}
461-
return false;
443+
includeDestructuredIfNecessary(): boolean {
444+
/* istanbul ignore next */
445+
this.scope.context.error(
446+
{
447+
message: 'includeDestructuredIfNecessary is currently not supported for MemberExpressions'
448+
},
449+
this.start
450+
);
462451
}
463452

464453
initialise(): void {

src/ast/nodes/ObjectPattern.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -87,25 +87,23 @@ export default class ObjectPattern extends NodeBase implements DeclarationPatter
8787
destructuredInitPath: ObjectPath,
8888
init: ExpressionEntity
8989
): boolean {
90-
if (!this.properties.length) return false;
90+
if (!this.properties.length) return this.included;
9191

9292
const lastProperty = this.properties.at(-1)!;
93-
const lastPropertyIncluded = lastProperty.includeDestructuredIfNecessary(
94-
context,
95-
destructuredInitPath,
96-
init
97-
);
93+
let included = lastProperty.includeDestructuredIfNecessary(context, destructuredInitPath, init);
9894
const lastPropertyIsRestElement = lastProperty.type === NodeType.RestElement;
9995

100-
let included = lastPropertyIsRestElement ? lastPropertyIncluded : false;
10196
for (const property of this.properties.slice(0, -1)) {
102-
if (lastPropertyIsRestElement && lastPropertyIncluded) {
97+
if (lastPropertyIsRestElement && included && !property.included) {
10398
property.includeNode(context);
10499
}
105100
included =
106101
property.includeDestructuredIfNecessary(context, destructuredInitPath, init) || included;
107102
}
108-
return (this.included ||= included);
103+
if (!this.included && included) {
104+
this.includeNode(context);
105+
}
106+
return this.included;
109107
}
110108

111109
markDeclarationReached(): void {

src/ast/nodes/Property.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,16 @@ export default class Property extends MethodBase implements DeclarationPatternNo
8484
if ((included ||= this.key.hasEffects(createHasEffectsContext()))) {
8585
this.key.include(context, false);
8686
if (!this.value.included) {
87-
this.value.included = true;
87+
this.value.includeNode(context);
8888
// Unfortunately, we need to include the value again now, so that any
8989
// declared variables are properly included.
9090
(this.value as PatternNode).includeDestructuredIfNecessary(context, path, init);
9191
}
9292
}
93-
return (this.included = included);
93+
if (!this.included && included) {
94+
this.includeNode(context);
95+
}
96+
return this.included;
9497
}
9598

9699
include(context: InclusionContext, includeChildrenRecursively: IncludeChildren) {

src/ast/nodes/RestElement.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,15 @@ export default class RestElement extends NodeBase implements DeclarationPatternN
7373
destructuredInitPath: ObjectPath,
7474
init: ExpressionEntity
7575
): boolean {
76-
return (this.included =
77-
this.argument.includeDestructuredIfNecessary(
78-
context,
79-
getIncludedPatternPath(destructuredInitPath),
80-
init
81-
) || this.included);
76+
const included = this.argument.includeDestructuredIfNecessary(
77+
context,
78+
getIncludedPatternPath(destructuredInitPath),
79+
init
80+
);
81+
if (!this.included && included) {
82+
this.includeNode(context);
83+
}
84+
return this.included;
8285
}
8386

8487
include(context: InclusionContext, includeChildrenRecursively: IncludeChildren) {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = defineTest({
2+
description: 'Keep the non-first assignment in destructuring unknown array variables',
3+
context: {
4+
unknownVariable: []
5+
}
6+
});
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
const [a, last2 = { foo: true }] = unknownVariable;
2+
assert.ok(last2.foo);

0 commit comments

Comments
 (0)