@@ -82,34 +82,20 @@ export function migrateFile(sourceFile: ts.SourceFile, options: MigrationOptions
8282 const tracker = new ChangeTracker ( printer ) ;
8383
8484 analysis . classes . forEach ( ( { node, constructor, superCall} ) => {
85- let removedStatements : Set < ts . Statement > | null = null ;
85+ const memberIndentation = getLeadingLineWhitespaceOfNode ( node . members [ 0 ] ) ;
86+ const prependToClass : string [ ] = [ ] ;
87+ const removedStatements = new Set < ts . Statement > ( ) ;
8688
8789 if ( options . _internalCombineMemberInitializers ) {
88- findUninitializedPropertiesToCombine ( node , constructor , localTypeChecker ) ?. forEach (
89- ( initializer , property ) => {
90- const statement = closestNode ( initializer , ts . isStatement ) ;
91-
92- if ( ! statement ) {
93- return ;
94- }
95-
96- const newProperty = ts . factory . createPropertyDeclaration (
97- cloneModifiers ( property . modifiers ) ,
98- cloneName ( property . name ) ,
99- property . questionToken ,
100- property . type ,
101- initializer ,
102- ) ;
103- tracker . replaceText (
104- statement . getSourceFile ( ) ,
105- statement . getFullStart ( ) ,
106- statement . getFullWidth ( ) ,
107- '' ,
108- ) ;
109- tracker . replaceNode ( property , newProperty ) ;
110- removedStatements = removedStatements || new Set ( ) ;
111- removedStatements . add ( statement ) ;
112- } ,
90+ applyInternalOnlyChanges (
91+ node ,
92+ constructor ,
93+ localTypeChecker ,
94+ tracker ,
95+ printer ,
96+ removedStatements ,
97+ prependToClass ,
98+ memberIndentation ,
11399 ) ;
114100 }
115101
@@ -118,6 +104,8 @@ export function migrateFile(sourceFile: ts.SourceFile, options: MigrationOptions
118104 constructor ,
119105 superCall ,
120106 options ,
107+ memberIndentation ,
108+ prependToClass ,
121109 removedStatements ,
122110 localTypeChecker ,
123111 printer ,
@@ -141,6 +129,8 @@ export function migrateFile(sourceFile: ts.SourceFile, options: MigrationOptions
141129 * @param constructor Reference to the class' constructor node.
142130 * @param superCall Reference to the constructor's `super()` call, if any.
143131 * @param options Options used to configure the migration.
132+ * @param memberIndentation Indentation string of the members of the class.
133+ * @param prependToClass Text that should be prepended to the class.
144134 * @param removedStatements Statements that have been removed from the constructor already.
145135 * @param localTypeChecker Type checker set up for the specific file.
146136 * @param printer Printer used to output AST nodes as strings.
@@ -151,7 +141,9 @@ function migrateClass(
151141 constructor : ts . ConstructorDeclaration ,
152142 superCall : ts . CallExpression | null ,
153143 options : MigrationOptions ,
154- removedStatements : Set < ts . Statement > | null ,
144+ memberIndentation : string ,
145+ prependToClass : string [ ] ,
146+ removedStatements : Set < ts . Statement > ,
155147 localTypeChecker : ts . TypeChecker ,
156148 printer : ts . Printer ,
157149 tracker : ChangeTracker ,
@@ -173,14 +165,12 @@ function migrateClass(
173165 const superParameters = superCall
174166 ? getSuperParameters ( constructor , superCall , localTypeChecker )
175167 : null ;
176- const memberIndentation = getLeadingLineWhitespaceOfNode ( node . members [ 0 ] ) ;
177- const removedStatementCount = removedStatements ?. size || 0 ;
168+ const removedStatementCount = removedStatements . size ;
178169 const innerReference =
179170 superCall ||
180- constructor . body ?. statements . find ( ( statement ) => ! removedStatements ? .has ( statement ) ) ||
171+ constructor . body ?. statements . find ( ( statement ) => ! removedStatements . has ( statement ) ) ||
181172 constructor ;
182173 const innerIndentation = getLeadingLineWhitespaceOfNode ( innerReference ) ;
183- const propsToAdd : string [ ] = [ ] ;
184174 const prependToConstructor : string [ ] = [ ] ;
185175 const afterSuper : string [ ] = [ ] ;
186176 const removedMembers = new Set < ts . ClassElement > ( ) ;
@@ -201,7 +191,7 @@ function migrateClass(
201191 memberIndentation ,
202192 innerIndentation ,
203193 prependToConstructor ,
204- propsToAdd ,
194+ prependToClass ,
205195 afterSuper ,
206196 ) ;
207197 }
@@ -249,21 +239,21 @@ function migrateClass(
249239
250240 // The new signature always has to be right before the constructor implementation.
251241 if ( memberReference === constructor ) {
252- propsToAdd . push ( extraSignature ) ;
242+ prependToClass . push ( extraSignature ) ;
253243 } else {
254244 tracker . insertText ( sourceFile , constructor . getFullStart ( ) , '\n' + extraSignature ) ;
255245 }
256246 }
257247
258- if ( propsToAdd . length > 0 ) {
248+ if ( prependToClass . length > 0 ) {
259249 if ( removedMembers . size === node . members . length ) {
260- tracker . insertText ( sourceFile , constructor . getEnd ( ) + 1 , `${ propsToAdd . join ( '\n' ) } \n` ) ;
250+ tracker . insertText ( sourceFile , constructor . getEnd ( ) + 1 , `${ prependToClass . join ( '\n' ) } \n` ) ;
261251 } else {
262252 // Insert the new properties after the first member that hasn't been deleted.
263253 tracker . insertText (
264254 sourceFile ,
265255 memberReference . getFullStart ( ) ,
266- `\n${ propsToAdd . join ( '\n' ) } \n` ,
256+ `\n${ prependToClass . join ( '\n' ) } \n` ,
267257 ) ;
268258 }
269259 }
@@ -685,3 +675,63 @@ function canRemoveConstructor(
685675 ( statementCount === 1 && superCall !== null && superCall . arguments . length === 0 )
686676 ) ;
687677}
678+
679+ /**
680+ * Applies the internal-specific migrations to a class.
681+ * @param node Class being migrated.
682+ * @param constructor The migrated class' constructor.
683+ * @param localTypeChecker File-specific type checker.
684+ * @param tracker Object keeping track of the changes.
685+ * @param printer Printer used to output AST nodes as text.
686+ * @param removedStatements Statements that have been removed by the migration.
687+ * @param prependToClass Text that will be prepended to a class.
688+ * @param memberIndentation Indentation string of the class' members.
689+ */
690+ function applyInternalOnlyChanges (
691+ node : ts . ClassDeclaration ,
692+ constructor : ts . ConstructorDeclaration ,
693+ localTypeChecker : ts . TypeChecker ,
694+ tracker : ChangeTracker ,
695+ printer : ts . Printer ,
696+ removedStatements : Set < ts . Statement > ,
697+ prependToClass : string [ ] ,
698+ memberIndentation : string ,
699+ ) {
700+ const result = findUninitializedPropertiesToCombine ( node , constructor , localTypeChecker ) ;
701+
702+ result ?. toCombine . forEach ( ( initializer , property ) => {
703+ const statement = closestNode ( initializer , ts . isStatement ) ;
704+
705+ if ( ! statement ) {
706+ return ;
707+ }
708+
709+ const newProperty = ts . factory . createPropertyDeclaration (
710+ cloneModifiers ( property . modifiers ) ,
711+ cloneName ( property . name ) ,
712+ property . questionToken ,
713+ property . type ,
714+ initializer ,
715+ ) ;
716+ tracker . replaceText (
717+ statement . getSourceFile ( ) ,
718+ statement . getFullStart ( ) ,
719+ statement . getFullWidth ( ) ,
720+ '' ,
721+ ) ;
722+ tracker . replaceNode ( property , newProperty ) ;
723+ removedStatements . add ( statement ) ;
724+ } ) ;
725+
726+ result ?. toHoist . forEach ( ( decl ) => {
727+ prependToClass . push (
728+ memberIndentation + printer . printNode ( ts . EmitHint . Unspecified , decl , decl . getSourceFile ( ) ) ,
729+ ) ;
730+ tracker . replaceText ( decl . getSourceFile ( ) , decl . getFullStart ( ) , decl . getFullWidth ( ) , '' ) ;
731+ } ) ;
732+
733+ // If we added any hoisted properties, separate them visually with a new line.
734+ if ( prependToClass . length > 0 ) {
735+ prependToClass . push ( '' ) ;
736+ }
737+ }
0 commit comments