Skip to content

Commit 9777fb9

Browse files
author
Joseph Watts
committed
Move class property transformation into new transformer.
Signed-off-by: Joseph Watts <[email protected]>
1 parent 0c9db71 commit 9777fb9

11 files changed

+807
-434
lines changed

src/compiler/binder.ts

+10-11
Original file line numberDiff line numberDiff line change
@@ -3223,8 +3223,7 @@ namespace ts {
32233223
// A ClassDeclaration is ES6 syntax.
32243224
transformFlags = subtreeFlags | TransformFlags.AssertES2015;
32253225

3226-
// A class with a parameter property assignment, property initializer, computed property name, or decorator is
3227-
// TypeScript syntax.
3226+
// A class with a parameter property assignment or decorator is TypeScript syntax.
32283227
// An exported declaration may be TypeScript syntax, but is handled by the visitor
32293228
// for a namespace declaration.
32303229
if ((subtreeFlags & TransformFlags.ContainsTypeScriptClassSyntax)
@@ -3241,8 +3240,7 @@ namespace ts {
32413240
// A ClassExpression is ES6 syntax.
32423241
let transformFlags = subtreeFlags | TransformFlags.AssertES2015;
32433242

3244-
// A class with a parameter property assignment, property initializer, or decorator is
3245-
// TypeScript syntax.
3243+
// A class with a parameter property assignment or decorator is TypeScript syntax.
32463244
if (subtreeFlags & TransformFlags.ContainsTypeScriptClassSyntax
32473245
|| node.typeParameters) {
32483246
transformFlags |= TransformFlags.AssertTypeScript;
@@ -3332,7 +3330,6 @@ namespace ts {
33323330
|| hasModifier(node, ModifierFlags.TypeScriptModifier)
33333331
|| node.typeParameters
33343332
|| node.type
3335-
|| (node.name && isComputedPropertyName(node.name)) // While computed method names aren't typescript, the TS transform must visit them to emit property declarations correctly
33363333
|| !node.body) {
33373334
transformFlags |= TransformFlags.AssertTypeScript;
33383335
}
@@ -3363,7 +3360,6 @@ namespace ts {
33633360
if (node.decorators
33643361
|| hasModifier(node, ModifierFlags.TypeScriptModifier)
33653362
|| node.type
3366-
|| (node.name && isComputedPropertyName(node.name)) // While computed accessor names aren't typescript, the TS transform must visit them to emit property declarations correctly
33673363
|| !node.body) {
33683364
transformFlags |= TransformFlags.AssertTypeScript;
33693365
}
@@ -3378,12 +3374,15 @@ namespace ts {
33783374
}
33793375

33803376
function computePropertyDeclaration(node: PropertyDeclaration, subtreeFlags: TransformFlags) {
3381-
// A PropertyDeclaration is TypeScript syntax.
3382-
let transformFlags = subtreeFlags | TransformFlags.AssertTypeScript;
3377+
let transformFlags = subtreeFlags | TransformFlags.ContainsClassFields;
3378+
3379+
// Decorators, TypeScript-specific modifiers, and type annotations are TypeScript syntax.
3380+
if (some(node.decorators) || hasModifier(node, ModifierFlags.TypeScriptModifier) || node.type) {
3381+
transformFlags |= TransformFlags.AssertTypeScript;
3382+
}
33833383

3384-
// If the PropertyDeclaration has an initializer or a computed name, we need to inform its ancestor
3385-
// so that it handle the transformation.
3386-
if (node.initializer || isComputedPropertyName(node.name)) {
3384+
// Hoisted variables related to class properties should live within the TypeScript class wrapper.
3385+
if (isComputedPropertyName(node.name) || (hasStaticModifier(node) && node.initializer)) {
33873386
transformFlags |= TransformFlags.ContainsTypeScriptClassSyntax;
33883387
}
33893388

src/compiler/transformer.ts

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ namespace ts {
4444
addRange(transformers, customTransformers && map(customTransformers.before, wrapScriptTransformerFactory));
4545

4646
transformers.push(transformTypeScript);
47+
transformers.push(transformClassFields);
4748

4849
if (jsx === JsxEmit.React) {
4950
transformers.push(transformJsx);

src/compiler/transformers/classFields.ts

+491
Large diffs are not rendered by default.

src/compiler/transformers/ts.ts

+146-347
Large diffs are not rendered by default.

src/compiler/transformers/utilities.ts

+80
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,47 @@ namespace ts {
240240
isIdentifier(expression);
241241
}
242242

243+
/**
244+
* A simple inlinable expression is an expression which can be copied into multiple locations
245+
* without risk of repeating any sideeffects and whose value could not possibly change between
246+
* any such locations
247+
*/
248+
export function isSimpleInlineableExpression(expression: Expression) {
249+
return !isIdentifier(expression) && isSimpleCopiableExpression(expression) ||
250+
isWellKnownSymbolSyntactically(expression);
251+
}
252+
253+
/**
254+
* Adds super call and preceding prologue directives into the list of statements.
255+
*
256+
* @param ctor The constructor node.
257+
* @param result The list of statements.
258+
* @param visitor The visitor to apply to each node added to the result array.
259+
* @returns index of the statement that follows super call
260+
*/
261+
export function addPrologueDirectivesAndInitialSuperCall(ctor: ConstructorDeclaration, result: Statement[], visitor: Visitor): number {
262+
if (ctor.body) {
263+
const statements = ctor.body.statements;
264+
// add prologue directives to the list (if any)
265+
const index = addPrologue(result, statements, /*ensureUseStrict*/ false, visitor);
266+
if (index === statements.length) {
267+
// list contains nothing but prologue directives (or empty) - exit
268+
return index;
269+
}
270+
271+
const statement = statements[index];
272+
if (statement.kind === SyntaxKind.ExpressionStatement && isSuperCall((<ExpressionStatement>statement).expression)) {
273+
result.push(visitNode(statement, visitor, isStatement));
274+
return index + 1;
275+
}
276+
277+
return index;
278+
}
279+
280+
return 0;
281+
}
282+
283+
243284
/**
244285
* @param input Template string input strings
245286
* @param args Names which need to be made file-level unique
@@ -255,4 +296,43 @@ namespace ts {
255296
return result;
256297
};
257298
}
299+
300+
/**
301+
* Gets all property declarations with initializers on either the static or instance side of a class.
302+
*
303+
* @param node The class node.
304+
* @param isStatic A value indicating whether to get properties from the static or instance side of the class.
305+
*/
306+
export function getInitializedProperties(node: ClassExpression | ClassDeclaration, isStatic: boolean): ReadonlyArray<PropertyDeclaration> {
307+
return filter(node.members, isStatic ? isStaticInitializedProperty : isInstanceInitializedProperty);
308+
}
309+
310+
/**
311+
* Gets a value indicating whether a class element is a static property declaration with an initializer.
312+
*
313+
* @param member The class element node.
314+
*/
315+
export function isStaticInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } {
316+
return isInitializedProperty(member) && hasStaticModifier(member);
317+
}
318+
319+
/**
320+
* Gets a value indicating whether a class element is an instance property declaration with an initializer.
321+
*
322+
* @param member The class element node.
323+
*/
324+
export function isInstanceInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } {
325+
return isInitializedProperty(member) && !hasStaticModifier(member);
326+
}
327+
328+
/**
329+
* Gets a value indicating whether a class element is either a static or an instance property declaration with an initializer.
330+
*
331+
* @param member The class element node.
332+
* @param isStatic A value indicating whether the member should be a static or instance member.
333+
*/
334+
export function isInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } {
335+
return member.kind === SyntaxKind.PropertyDeclaration
336+
&& (<PropertyDeclaration>member).initializer !== undefined;
337+
}
258338
}

src/compiler/tsconfig.json

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"transformers/utilities.ts",
3030
"transformers/destructuring.ts",
3131
"transformers/ts.ts",
32+
"transformers/classFields.ts",
3233
"transformers/es2017.ts",
3334
"transformers/es2018.ts",
3435
"transformers/es2019.ts",

src/compiler/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5183,6 +5183,7 @@ namespace ts {
51835183
ContainsYield = 1 << 17,
51845184
ContainsHoistedDeclarationOrCompletion = 1 << 18,
51855185
ContainsDynamicImport = 1 << 19,
5186+
ContainsClassFields = 1 << 20,
51865187

51875188
// Please leave this as 1 << 29.
51885189
// It is the maximum bit we can set before we outgrow the size of a v8 small integer (SMI) on an x86 system.

tests/baselines/reference/declarationEmitPrivateSymbolCausesVarDeclarationEmit2.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ var C = /** @class */ (function () {
3434
}
3535
return C;
3636
}());
37-
_a = a_1.x;
3837
exports.C = C;
38+
_a = a_1.x;
3939
//// [c.js]
4040
"use strict";
4141
var __extends = (this && this.__extends) || (function () {
@@ -64,8 +64,8 @@ var D = /** @class */ (function (_super) {
6464
}
6565
return D;
6666
}(b_1.C));
67-
_a = a_1.x;
6867
exports.D = D;
68+
_a = a_1.x;
6969

7070

7171
//// [a.d.ts]

0 commit comments

Comments
 (0)