Skip to content

Commit dd7c993

Browse files
author
Joseph Watts
committed
Clean up private field class transformation.
Signed-off-by: Joseph Watts <[email protected]>
1 parent 8ce239f commit dd7c993

File tree

1 file changed

+66
-53
lines changed

1 file changed

+66
-53
lines changed

src/compiler/transformers/esnext.ts

Lines changed: 66 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,9 @@ namespace ts {
116116
case SyntaxKind.PropertyAccessExpression:
117117
return visitPropertyAccessExpression(node as PropertyAccessExpression);
118118
case SyntaxKind.ClassDeclaration:
119+
return visitClassDeclaration(node as ClassDeclaration);
119120
case SyntaxKind.ClassExpression:
120-
return visitClassLikeDeclaration(node as ClassLikeDeclaration);
121+
return visitClassExpression(node as ClassExpression);
121122
default:
122123
return visitEachChild(node, visitor, context);
123124
}
@@ -159,12 +160,42 @@ namespace ts {
159160
return visitEachChild(node, visitor, context);
160161
}
161162

162-
function visitClassLikeDeclaration(node: ClassLikeDeclaration): Node[] {
163+
function visitClassDeclaration(node: ClassDeclaration) {
164+
startPrivateNameEnvironment();
165+
node = visitEachChild(node, visitor, context);
166+
node = updateClassDeclaration(
167+
node,
168+
node.decorators,
169+
node.modifiers,
170+
node.name,
171+
node.typeParameters,
172+
node.heritageClauses,
173+
transformClassMembers(node.members)
174+
);
175+
return [...endPrivateNameEnvironment(), node];
176+
}
177+
178+
function visitClassExpression(node: ClassExpression) {
179+
startPrivateNameEnvironment();
180+
node = visitEachChild(node, visitor, context);
181+
node = updateClassExpression(
182+
node,
183+
node.modifiers,
184+
node.name,
185+
node.typeParameters,
186+
node.heritageClauses,
187+
transformClassMembers(node.members)
188+
);
189+
return [...endPrivateNameEnvironment(), node];
190+
}
191+
192+
function startPrivateNameEnvironment() {
163193
// Create private name environment.
164194
privateNameEnvironmentStack[++privateNameEnvironmentIndex] = {};
165-
// Visit children.
166-
node = visitEachChild(node, visitor, context);
167-
// Create WeakMaps for private properties.
195+
return currentPrivateNameEnvironment();
196+
}
197+
198+
function endPrivateNameEnvironment(): Statement[] {
168199
const privateNameEnvironment = currentPrivateNameEnvironment();
169200
const weakMapDeclarations = Object.keys(privateNameEnvironment).map(name => {
170201
const weakMapName = privateNameEnvironment[name];
@@ -179,6 +210,15 @@ namespace ts {
179210
))]
180211
);
181212
});
213+
// Destroy private name environment.
214+
delete privateNameEnvironmentStack[privateNameEnvironmentIndex--];
215+
return weakMapDeclarations;
216+
}
217+
218+
function transformClassMembers(members: ReadonlyArray<ClassElement>): ClassElement[] {
219+
// Rewrite constructor with private name initializers.
220+
const privateNameEnvironment = currentPrivateNameEnvironment();
221+
// Initialize private properties.
182222
const initializerStatements = Object.keys(privateNameEnvironment).map(name => {
183223
return createStatement(
184224
createCall(
@@ -188,60 +228,33 @@ namespace ts {
188228
)
189229
);
190230
});
191-
let members = [...node.members];
192-
let ctor = find(members, (member) => isConstructorDeclaration(member));
193-
if (!ctor) {
194-
// Create constructor with private field initializers.
195-
ctor = createConstructor(
196-
/* decorators */ undefined,
197-
/* modifiers */ undefined,
198-
/* parameters */ [],
199-
createBlock(initializerStatements)
200-
);
201-
members.unshift(ctor);
202-
} else {
203-
// Update existing constructor to add private field initializers.
204-
members = members.map(member => {
231+
const ctor = find(members, (member) => isConstructorDeclaration(member)) as ConstructorDeclaration | undefined;
232+
if (ctor) {
233+
const body = ctor.body ?
234+
updateBlock(ctor.body, [...initializerStatements, ...ctor.body.statements]) :
235+
createBlock(initializerStatements, /* multiLine */ undefined);
236+
return members.map(member => {
205237
if (isConstructorDeclaration(member)) {
206-
let statements = member.body ?
207-
[...initializerStatements, ...member.body.statements] :
208-
initializerStatements;
209238
return updateConstructor(
210-
member,
211-
member.decorators,
212-
member.modifiers,
213-
member.parameters,
214-
createBlock(statements, member.body ? member.body.multiLine : undefined)
239+
ctor,
240+
ctor.decorators,
241+
ctor.modifiers,
242+
ctor.parameters,
243+
body
215244
);
216245
}
217246
return member;
218-
})
219-
}
220-
221-
// Update class members.
222-
if (isClassDeclaration(node)) {
223-
node = updateClassDeclaration(
224-
node,
225-
node.decorators,
226-
node.modifiers,
227-
node.name,
228-
node.typeParameters,
229-
node.heritageClauses,
230-
members
231-
);
232-
} else if (isClassExpression(node)) {
233-
node = updateClassExpression(
234-
node,
235-
node.modifiers,
236-
node.name,
237-
node.typeParameters,
238-
node.heritageClauses,
239-
members
240-
);
247+
});
241248
}
242-
// Destroy private name environment.
243-
delete privateNameEnvironmentStack[privateNameEnvironmentIndex--];
244-
return [ ...weakMapDeclarations, node ];
249+
return [
250+
createConstructor(
251+
/* decorators */ undefined,
252+
/* modifiers */ undefined,
253+
/* parameters */ [],
254+
createBlock(initializerStatements)
255+
),
256+
...members
257+
];
245258
}
246259

247260
function visitAwaitExpression(node: AwaitExpression): Expression {

0 commit comments

Comments
 (0)