Skip to content

Commit f986800

Browse files
author
Joseph Watts
committed
Transform private name bindings in destructuring assignments
Signed-off-by: Joseph Watts <[email protected]>
1 parent 083b4cb commit f986800

File tree

3 files changed

+101
-8
lines changed

3 files changed

+101
-8
lines changed

src/compiler/transformers/esnext.ts

+93-8
Original file line numberDiff line numberDiff line change
@@ -758,20 +758,105 @@ namespace ts {
758758
return visitEachChild(node, visitor, context);
759759
}
760760

761+
function wrapPrivateNameForDestructuringTarget(node: PrivateNamedPropertyAccess) {
762+
return createPropertyAccess(
763+
createObjectLiteral([
764+
createSetAccessor(
765+
/*decorators*/ undefined,
766+
/*modifiers*/ undefined,
767+
"value",
768+
[createParameter(
769+
/*decorators*/ undefined,
770+
/*modifiers*/ undefined,
771+
/*dotDotDotToken*/ undefined, "x",
772+
/*questionToken*/ undefined,
773+
/*type*/ undefined,
774+
/*initializer*/ undefined
775+
)],
776+
createBlock(
777+
[createExpressionStatement(
778+
createAssignment(
779+
visitNode(node, visitor),
780+
createIdentifier("x")
781+
)
782+
)]
783+
)
784+
)
785+
]),
786+
"value"
787+
);
788+
}
789+
790+
function transformDestructuringAssignmentTarget(node: ArrayLiteralExpression | ObjectLiteralExpression) {
791+
const hasPrivateNames = isArrayLiteralExpression(node) ?
792+
forEach(node.elements, isPrivateNamedPropertyAccess) :
793+
forEach(node.properties, property => isPropertyAssignment(property) && isPrivateNamedPropertyAccess(property.initializer));
794+
if (!hasPrivateNames) {
795+
return node;
796+
}
797+
if (isArrayLiteralExpression(node)) {
798+
// Transforms private names in destructuring assignment array bindings.
799+
//
800+
// Source:
801+
// ([ this.#myProp ] = [ "hello" ]);
802+
//
803+
// Transformation:
804+
// [ { set value(x) { this.#myProp = x; } }.value ] = [ "hello" ];
805+
return updateArrayLiteral(
806+
node,
807+
node.elements.map(
808+
expr => isPrivateNamedPropertyAccess(expr) ?
809+
wrapPrivateNameForDestructuringTarget(expr) :
810+
expr
811+
)
812+
);
813+
}
814+
else {
815+
// Transforms private names in destructuring assignment object bindings.
816+
//
817+
// Source:
818+
// ({ stringProperty: this.#myProp } = { stringProperty: "hello" });
819+
//
820+
// Transformation:
821+
// ({ stringProperty: { set value(x) { this.#myProp = x; } }.value }) = { stringProperty: "hello" };
822+
return updateObjectLiteral(
823+
node,
824+
node.properties.map(
825+
prop => isPropertyAssignment(prop) && isPrivateNamedPropertyAccess(prop.initializer) ?
826+
updatePropertyAssignment(
827+
prop,
828+
prop.name,
829+
wrapPrivateNameForDestructuringTarget(prop.initializer)
830+
) :
831+
prop
832+
)
833+
);
834+
}
835+
}
836+
761837
/**
762838
* Visits a BinaryExpression that contains a destructuring assignment.
763839
*
764840
* @param node A BinaryExpression node.
765841
*/
766842
function visitBinaryExpression(node: BinaryExpression, noDestructuringValue: boolean): Expression {
767-
if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
768-
return flattenDestructuringAssignment(
769-
node,
770-
visitor,
771-
context,
772-
FlattenLevel.ObjectRest,
773-
!noDestructuringValue
774-
);
843+
if (isDestructuringAssignment(node)) {
844+
const left = transformDestructuringAssignmentTarget(node.left);
845+
if (left !== node.left || node.left.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
846+
return flattenDestructuringAssignment(
847+
left === node.left ? node : updateBinary(
848+
node,
849+
left,
850+
node.right,
851+
node.operatorToken.kind
852+
) as DestructuringAssignment,
853+
visitor,
854+
context,
855+
node.left.transformFlags & TransformFlags.ContainsObjectRestOrSpread
856+
? FlattenLevel.ObjectRest : FlattenLevel.All,
857+
!noDestructuringValue
858+
);
859+
}
775860
}
776861
else if (node.operatorToken.kind === SyntaxKind.CommaToken) {
777862
return updateBinary(

src/compiler/types.ts

+4
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

+4
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)