Skip to content

Commit 490549c

Browse files
author
Joseph Watts
committed
Transform private name bindings in destructuring assignments
1 parent 5a12944 commit 490549c

File tree

3 files changed

+101
-8
lines changed

3 files changed

+101
-8
lines changed

src/compiler/transformers/esnext.ts

Lines changed: 93 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -723,20 +723,105 @@ namespace ts {
723723
return visitEachChild(node, visitor, context);
724724
}
725725

726+
function wrapPrivateNameForDestructuringTarget(node: PrivateNamedPropertyAccess) {
727+
return createPropertyAccess(
728+
createObjectLiteral([
729+
createSetAccessor(
730+
/*decorators*/ undefined,
731+
/*modifiers*/ undefined,
732+
"value",
733+
[createParameter(
734+
/*decorators*/ undefined,
735+
/*modifiers*/ undefined,
736+
/*dotDotDotToken*/ undefined, "x",
737+
/*questionToken*/ undefined,
738+
/*type*/ undefined,
739+
/*initializer*/ undefined
740+
)],
741+
createBlock(
742+
[createExpressionStatement(
743+
createAssignment(
744+
visitNode(node, visitor, isPrivateNamedPropertyAccess),
745+
createIdentifier("x")
746+
)
747+
)]
748+
)
749+
)
750+
]),
751+
"value"
752+
);
753+
}
754+
755+
function transformDestructuringAssignmentTarget(node: ArrayLiteralExpression | ObjectLiteralExpression) {
756+
const hasPrivateNames = isArrayLiteralExpression(node) ?
757+
forEach(node.elements, isPrivateNamedPropertyAccess) :
758+
forEach(node.properties, property => isPropertyAssignment(property) && isPrivateNamedPropertyAccess(property.initializer));
759+
if (!hasPrivateNames) {
760+
return node;
761+
}
762+
if (isArrayLiteralExpression(node)) {
763+
// Transforms private names in destructuring assignment array bindings.
764+
//
765+
// Source:
766+
// ([ this.#myProp ] = [ "hello" ]);
767+
//
768+
// Transformation:
769+
// [ { set value(x) { this.#myProp = x; } }.value ] = [ "hello" ];
770+
return updateArrayLiteral(
771+
node,
772+
node.elements.map(
773+
expr => isPrivateNamedPropertyAccess(expr) ?
774+
wrapPrivateNameForDestructuringTarget(expr) :
775+
expr
776+
)
777+
);
778+
}
779+
else {
780+
// Transforms private names in destructuring assignment object bindings.
781+
//
782+
// Source:
783+
// ({ stringProperty: this.#myProp } = { stringProperty: "hello" });
784+
//
785+
// Transformation:
786+
// ({ stringProperty: { set value(x) { this.#myProp = x; } }.value }) = { stringProperty: "hello" };
787+
return updateObjectLiteral(
788+
node,
789+
node.properties.map(
790+
prop => isPropertyAssignment(prop) && isPrivateNamedPropertyAccess(prop.initializer) ?
791+
updatePropertyAssignment(
792+
prop,
793+
prop.name,
794+
wrapPrivateNameForDestructuringTarget(prop.initializer)
795+
) :
796+
prop
797+
)
798+
);
799+
}
800+
}
801+
726802
/**
727803
* Visits a BinaryExpression that contains a destructuring assignment.
728804
*
729805
* @param node A BinaryExpression node.
730806
*/
731807
function visitBinaryExpression(node: BinaryExpression, noDestructuringValue: boolean): Expression {
732-
if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.ContainsObjectRest) {
733-
return flattenDestructuringAssignment(
734-
node,
735-
visitor,
736-
context,
737-
FlattenLevel.ObjectRest,
738-
!noDestructuringValue
739-
);
808+
if (isDestructuringAssignment(node)) {
809+
const left = transformDestructuringAssignmentTarget(node.left);
810+
if (left !== node.left || node.left.transformFlags & TransformFlags.ContainsObjectRest) {
811+
return flattenDestructuringAssignment(
812+
left === node.left ? node : updateBinary(
813+
node,
814+
left,
815+
node.right,
816+
node.operatorToken.kind
817+
) as DestructuringAssignment,
818+
visitor,
819+
context,
820+
node.left.transformFlags & TransformFlags.ContainsObjectRest
821+
? FlattenLevel.ObjectRest : FlattenLevel.All,
822+
!noDestructuringValue
823+
);
824+
}
740825
}
741826
else if (node.operatorToken.kind === SyntaxKind.CommaToken) {
742827
return updateBinary(

src/compiler/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,6 +1676,10 @@ namespace ts {
16761676
name: Identifier | PrivateName;
16771677
}
16781678

1679+
export interface PrivateNamedPropertyAccess extends PropertyAccessExpression {
1680+
name: PrivateName;
1681+
}
1682+
16791683
export interface SuperPropertyAccessExpression extends PropertyAccessExpression {
16801684
expression: SuperExpression;
16811685
}

src/compiler/utilities.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5985,6 +5985,10 @@ namespace ts {
59855985
return isPropertyDeclaration(node) && isPrivateName(node.name);
59865986
}
59875987

5988+
export function isPrivateNamedPropertyAccess(node: Node): node is PrivateNamedPropertyAccess {
5989+
return isPropertyAccessExpression(node) && isPrivateName(node.name);
5990+
}
5991+
59885992
export function isBindingName(node: Node): node is BindingName {
59895993
const kind = node.kind;
59905994
return kind === SyntaxKind.Identifier

0 commit comments

Comments
 (0)