Skip to content

Commit b0669ba

Browse files
author
Joseph Watts
committed
Transform private name bindings in destructuring assignments
1 parent c527c53 commit b0669ba

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
@@ -740,20 +740,105 @@ namespace ts {
740740
return visitEachChild(node, visitor, context);
741741
}
742742

743+
function wrapPrivateNameForDestructuringTarget(node: PrivateNamedPropertyAccess) {
744+
return createPropertyAccess(
745+
createObjectLiteral([
746+
createSetAccessor(
747+
/*decorators*/ undefined,
748+
/*modifiers*/ undefined,
749+
"value",
750+
[createParameter(
751+
/*decorators*/ undefined,
752+
/*modifiers*/ undefined,
753+
/*dotDotDotToken*/ undefined, "x",
754+
/*questionToken*/ undefined,
755+
/*type*/ undefined,
756+
/*initializer*/ undefined
757+
)],
758+
createBlock(
759+
[createExpressionStatement(
760+
createAssignment(
761+
visitNode(node, visitor, isPrivateNamedPropertyAccess),
762+
createIdentifier("x")
763+
)
764+
)]
765+
)
766+
)
767+
]),
768+
"value"
769+
);
770+
}
771+
772+
function transformDestructuringAssignmentTarget(node: ArrayLiteralExpression | ObjectLiteralExpression) {
773+
const hasPrivateNames = isArrayLiteralExpression(node) ?
774+
forEach(node.elements, isPrivateNamedPropertyAccess) :
775+
forEach(node.properties, property => isPropertyAssignment(property) && isPrivateNamedPropertyAccess(property.initializer));
776+
if (!hasPrivateNames) {
777+
return node;
778+
}
779+
if (isArrayLiteralExpression(node)) {
780+
// Transforms private names in destructuring assignment array bindings.
781+
//
782+
// Source:
783+
// ([ this.#myProp ] = [ "hello" ]);
784+
//
785+
// Transformation:
786+
// [ { set value(x) { this.#myProp = x; } }.value ] = [ "hello" ];
787+
return updateArrayLiteral(
788+
node,
789+
node.elements.map(
790+
expr => isPrivateNamedPropertyAccess(expr) ?
791+
wrapPrivateNameForDestructuringTarget(expr) :
792+
expr
793+
)
794+
);
795+
}
796+
else {
797+
// Transforms private names in destructuring assignment object bindings.
798+
//
799+
// Source:
800+
// ({ stringProperty: this.#myProp } = { stringProperty: "hello" });
801+
//
802+
// Transformation:
803+
// ({ stringProperty: { set value(x) { this.#myProp = x; } }.value }) = { stringProperty: "hello" };
804+
return updateObjectLiteral(
805+
node,
806+
node.properties.map(
807+
prop => isPropertyAssignment(prop) && isPrivateNamedPropertyAccess(prop.initializer) ?
808+
updatePropertyAssignment(
809+
prop,
810+
prop.name,
811+
wrapPrivateNameForDestructuringTarget(prop.initializer)
812+
) :
813+
prop
814+
)
815+
);
816+
}
817+
}
818+
743819
/**
744820
* Visits a BinaryExpression that contains a destructuring assignment.
745821
*
746822
* @param node A BinaryExpression node.
747823
*/
748824
function visitBinaryExpression(node: BinaryExpression, noDestructuringValue: boolean): Expression {
749-
if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
750-
return flattenDestructuringAssignment(
751-
node,
752-
visitor,
753-
context,
754-
FlattenLevel.ObjectRest,
755-
!noDestructuringValue
756-
);
825+
if (isDestructuringAssignment(node)) {
826+
const left = transformDestructuringAssignmentTarget(node.left);
827+
if (left !== node.left || node.left.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
828+
return flattenDestructuringAssignment(
829+
left === node.left ? node : updateBinary(
830+
node,
831+
left,
832+
node.right,
833+
node.operatorToken.kind
834+
) as DestructuringAssignment,
835+
visitor,
836+
context,
837+
node.left.transformFlags & TransformFlags.ContainsObjectRestOrSpread
838+
? FlattenLevel.ObjectRest : FlattenLevel.All,
839+
!noDestructuringValue
840+
);
841+
}
757842
}
758843
else if (node.operatorToken.kind === SyntaxKind.CommaToken) {
759844
return updateBinary(

src/compiler/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1756,6 +1756,10 @@ namespace ts {
17561756
name: Identifier | PrivateName;
17571757
}
17581758

1759+
export interface PrivateNamedPropertyAccess extends PropertyAccessExpression {
1760+
name: PrivateName;
1761+
}
1762+
17591763
export interface SuperPropertyAccessExpression extends PropertyAccessExpression {
17601764
expression: SuperExpression;
17611765
}

src/compiler/utilities.ts

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

6079+
export function isPrivateNamedPropertyAccess(node: Node): node is PrivateNamedPropertyAccess {
6080+
return isPropertyAccessExpression(node) && isPrivateName(node.name);
6081+
}
6082+
60796083
export function isBindingName(node: Node): node is BindingName {
60806084
const kind = node.kind;
60816085
return kind === SyntaxKind.Identifier

0 commit comments

Comments
 (0)