@@ -68,52 +68,88 @@ namespace ts {
6868 function visitClassDeclaration ( node : ClassDeclaration ) : VisitResult < Statement > {
6969 if ( ! ( classOrConstructorParameterIsDecorated ( node ) || childIsDecorated ( node ) ) ) return visitEachChild ( node , visitor , context ) ;
7070
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 ) ;
8174
8275 if ( statements . length > 1 ) {
8376 // Add a DeclarationMarker as a marker for the end of the declaration
8477 statements . push ( factory . createEndOfDeclarationMarker ( node ) ) ;
85- setEmitFlags ( classStatement , getEmitFlags ( classStatement ) | EmitFlags . HasEndOfDeclarationMarker ) ;
78+ setEmitFlags ( statements [ 0 ] , getEmitFlags ( statements [ 0 ] ) | EmitFlags . HasEndOfDeclarationMarker ) ;
8679 }
8780
8881 return singleOrMany ( statements ) ;
8982 }
9083
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+
91118 /**
92119 * Transforms a non-decorated class declaration.
93120 *
94121 * @param node A ClassDeclaration node.
95122 * @param name The name of the class.
96123 */
97- function createClassDeclarationHeadWithoutDecorators ( node : ClassDeclaration , name : Identifier | undefined ) {
124+ function transformClassDeclarationWithoutClassDecorators ( node : ClassDeclaration , name : Identifier | undefined ) {
98125 // ${modifiers} class ${name} ${heritageClauses} {
99126 // ${members}
100127 // }
101128
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 (
103137 node ,
104- visitNodes ( node . modifiers , modifierVisitor , isModifier ) ,
138+ modifiers ,
105139 name ,
106140 /*typeParameters*/ undefined ,
107- visitNodes ( node . heritageClauses , visitor , isHeritageClause ) ,
108- visitNodes ( node . members , visitor , isClassElement )
141+ heritageClauses ,
142+ members
109143 ) ;
144+
145+ return addRange ( [ updated ] , decorationStatements ) ;
110146 }
111147
112148 /**
113149 * Transforms a decorated class declaration and appends the resulting statements. If
114150 * the class requires an alias to avoid issues with double-binding, the alias is returned.
115151 */
116- function createClassDeclarationHeadWithDecorators ( node : ClassDeclaration , name : Identifier | undefined ) {
152+ function transformClassDeclarationWithClassDecorators ( node : ClassDeclaration , name : Identifier | undefined ) {
117153 // When we emit an ES6 class that has a class decorator, we must tailor the
118154 // emit to certain specific cases.
119155 //
@@ -213,8 +249,18 @@ namespace ts {
213249 // ${members}
214250 // }
215251 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+
218264 setOriginalNode ( classExpression , node ) ;
219265 setTextRange ( classExpression , location ) ;
220266
@@ -234,7 +280,11 @@ namespace ts {
234280 setOriginalNode ( statement , node ) ;
235281 setTextRange ( statement , location ) ;
236282 setCommentRange ( statement , node ) ;
237- return statement ;
283+
284+ const statements : Statement [ ] = [ statement ] ;
285+ addRange ( statements , decorationStatements ) ;
286+ addConstructorDecorationStatement ( statements , node ) ;
287+ return statements ;
238288 }
239289
240290 function visitClassExpression ( node : ClassExpression ) {
0 commit comments