@@ -68,52 +68,88 @@ namespace ts {
68
68
function visitClassDeclaration ( node : ClassDeclaration ) : VisitResult < Statement > {
69
69
if ( ! ( classOrConstructorParameterIsDecorated ( node ) || childIsDecorated ( node ) ) ) return visitEachChild ( node , visitor , context ) ;
70
70
71
- const classStatement = hasDecorators ( node ) ?
72
- createClassDeclarationHeadWithDecorators ( node , node . name ) :
73
- createClassDeclarationHeadWithoutDecorators ( node , node . name ) ;
74
-
75
- const statements : Statement [ ] = [ classStatement ] ;
76
-
77
- // Write any decorators of the node.
78
- addClassElementDecorationStatements ( statements , node , /*isStatic*/ false ) ;
79
- addClassElementDecorationStatements ( statements , node , /*isStatic*/ true ) ;
80
- addConstructorDecorationStatement ( statements , node ) ;
71
+ const statements = hasDecorators ( node ) ?
72
+ transformClassDeclarationWithClassDecorators ( node , node . name ) :
73
+ transformClassDeclarationWithoutClassDecorators ( node , node . name ) ;
81
74
82
75
if ( statements . length > 1 ) {
83
76
// Add a DeclarationMarker as a marker for the end of the declaration
84
77
statements . push ( factory . createEndOfDeclarationMarker ( node ) ) ;
85
- setEmitFlags ( classStatement , getEmitFlags ( classStatement ) | EmitFlags . HasEndOfDeclarationMarker ) ;
78
+ setEmitFlags ( statements [ 0 ] , getEmitFlags ( statements [ 0 ] ) | EmitFlags . HasEndOfDeclarationMarker ) ;
86
79
}
87
80
88
81
return singleOrMany ( statements ) ;
89
82
}
90
83
84
+ function decoratorContainsPrivateIdentifierInExpression ( decorator : Decorator ) {
85
+ return ! ! ( decorator . transformFlags & TransformFlags . ContainsPrivateIdentifierInExpression ) ;
86
+ }
87
+
88
+ function parameterDecoratorsContainPrivateIdentifierInExpression ( parameterDecorators : readonly Decorator [ ] | undefined ) {
89
+ return some ( parameterDecorators , decoratorContainsPrivateIdentifierInExpression ) ;
90
+ }
91
+
92
+ function hasClassElementWithDecoratorContainingPrivateIdentifierInExpression ( node : ClassDeclaration ) {
93
+ for ( const member of node . members ) {
94
+ if ( ! canHaveDecorators ( member ) ) continue ;
95
+ const allDecorators = getAllDecoratorsOfClassElement ( member , node ) ;
96
+ if ( some ( allDecorators ?. decorators , decoratorContainsPrivateIdentifierInExpression ) ) return true ;
97
+ if ( some ( allDecorators ?. parameters , parameterDecoratorsContainPrivateIdentifierInExpression ) ) return true ;
98
+ }
99
+ return false ;
100
+ }
101
+
102
+ function transformDecoratorsOfClassElements ( node : ClassDeclaration , members : NodeArray < ClassElement > ) {
103
+ let decorationStatements : Statement [ ] | undefined = [ ] ;
104
+ addClassElementDecorationStatements ( decorationStatements , node , /*isStatic*/ false ) ;
105
+ addClassElementDecorationStatements ( decorationStatements , node , /*isStatic*/ true ) ;
106
+ if ( hasClassElementWithDecoratorContainingPrivateIdentifierInExpression ( node ) ) {
107
+ members = setTextRange ( factory . createNodeArray ( [
108
+ ...members ,
109
+ factory . createClassStaticBlockDeclaration (
110
+ factory . createBlock ( decorationStatements , /*multiLine*/ true )
111
+ )
112
+ ] ) , members ) ;
113
+ decorationStatements = undefined ;
114
+ }
115
+ return { decorationStatements, members } ;
116
+ }
117
+
91
118
/**
92
119
* Transforms a non-decorated class declaration.
93
120
*
94
121
* @param node A ClassDeclaration node.
95
122
* @param name The name of the class.
96
123
*/
97
- function createClassDeclarationHeadWithoutDecorators ( node : ClassDeclaration , name : Identifier | undefined ) {
124
+ function transformClassDeclarationWithoutClassDecorators ( node : ClassDeclaration , name : Identifier | undefined ) {
98
125
// ${modifiers} class ${name} ${heritageClauses} {
99
126
// ${members}
100
127
// }
101
128
102
- return factory . updateClassDeclaration (
129
+ const modifiers = visitNodes ( node . modifiers , modifierVisitor , isModifier ) ;
130
+ const heritageClauses = visitNodes ( node . heritageClauses , visitor , isHeritageClause ) ;
131
+ let members = visitNodes ( node . members , visitor , isClassElement ) ;
132
+
133
+ let decorationStatements : Statement [ ] | undefined = [ ] ;
134
+ ( { members, decorationStatements } = transformDecoratorsOfClassElements ( node , members ) ) ;
135
+
136
+ const updated = factory . updateClassDeclaration (
103
137
node ,
104
- visitNodes ( node . modifiers , modifierVisitor , isModifier ) ,
138
+ modifiers ,
105
139
name ,
106
140
/*typeParameters*/ undefined ,
107
- visitNodes ( node . heritageClauses , visitor , isHeritageClause ) ,
108
- visitNodes ( node . members , visitor , isClassElement )
141
+ heritageClauses ,
142
+ members
109
143
) ;
144
+
145
+ return addRange ( [ updated ] , decorationStatements ) ;
110
146
}
111
147
112
148
/**
113
149
* Transforms a decorated class declaration and appends the resulting statements. If
114
150
* the class requires an alias to avoid issues with double-binding, the alias is returned.
115
151
*/
116
- function createClassDeclarationHeadWithDecorators ( node : ClassDeclaration , name : Identifier | undefined ) {
152
+ function transformClassDeclarationWithClassDecorators ( node : ClassDeclaration , name : Identifier | undefined ) {
117
153
// When we emit an ES6 class that has a class decorator, we must tailor the
118
154
// emit to certain specific cases.
119
155
//
@@ -213,8 +249,18 @@ namespace ts {
213
249
// ${members}
214
250
// }
215
251
const heritageClauses = visitNodes ( node . heritageClauses , visitor , isHeritageClause ) ;
216
- const members = visitNodes ( node . members , visitor , isClassElement ) ;
217
- const classExpression = factory . createClassExpression ( /*modifiers*/ undefined , name , /*typeParameters*/ undefined , heritageClauses , members ) ;
252
+ let members = visitNodes ( node . members , visitor , isClassElement ) ;
253
+
254
+ let decorationStatements : Statement [ ] | undefined = [ ] ;
255
+ ( { members, decorationStatements } = transformDecoratorsOfClassElements ( node , members ) ) ;
256
+
257
+ const classExpression = factory . createClassExpression (
258
+ /*modifiers*/ undefined ,
259
+ name ,
260
+ /*typeParameters*/ undefined ,
261
+ heritageClauses ,
262
+ members ) ;
263
+
218
264
setOriginalNode ( classExpression , node ) ;
219
265
setTextRange ( classExpression , location ) ;
220
266
@@ -234,7 +280,11 @@ namespace ts {
234
280
setOriginalNode ( statement , node ) ;
235
281
setTextRange ( statement , location ) ;
236
282
setCommentRange ( statement , node ) ;
237
- return statement ;
283
+
284
+ const statements : Statement [ ] = [ statement ] ;
285
+ addRange ( statements , decorationStatements ) ;
286
+ addConstructorDecorationStatement ( statements , node ) ;
287
+ return statements ;
238
288
}
239
289
240
290
function visitClassExpression ( node : ClassExpression ) {
0 commit comments