@@ -11,7 +11,7 @@ import {analyzeControlFlow, ControlFlowAnalysisNode} from '../../../flow_analysi
1111import { ProgramInfo , projectFile , Replacement , TextUpdate } from '../../../../../../utils/tsurge' ;
1212import { traverseAccess } from '../../../utils/traverse_access' ;
1313import { UniqueNamesGenerator } from '../../../utils/unique_names' ;
14- import { createNewBlockToInsertVariable } from '../helpers /create_block_arrow_function' ;
14+ import { createNewBlockToInsertVariable } from './create_block_arrow_function' ;
1515import assert from 'assert' ;
1616
1717export interface NarrowableTsReferences {
@@ -123,6 +123,26 @@ export function migrateStandardTsReference(
123123 replacements . push (
124124 ...createNewBlockToInsertVariable ( parent , filePath , temporaryVariableStr ) ,
125125 ) ;
126+ } else if (
127+ ts . isBlock ( recommendedNode ) &&
128+ shouldInsertAtMethodStart ( reference , recommendedNode , referenceNodeInBlock )
129+ ) {
130+ const blockStart = recommendedNode . getStart ( ) + 1 ;
131+ const firstStatement = recommendedNode . statements [ 0 ] ;
132+ const leadingSpace = firstStatement
133+ ? ts . getLineAndCharacterOfPosition ( sf , firstStatement . getStart ( ) )
134+ : ts . getLineAndCharacterOfPosition ( sf , referenceNodeInBlock . getStart ( ) ) ;
135+
136+ replacements . push (
137+ new Replacement (
138+ filePath ,
139+ new TextUpdate ( {
140+ position : blockStart ,
141+ end : blockStart ,
142+ toInsert : `${ ' ' . repeat ( leadingSpace . character ) } ${ temporaryVariableStr } \n${ ' ' . repeat ( leadingSpace . character ) } ` ,
143+ } ) ,
144+ ) ,
145+ ) ;
126146 } else {
127147 const leadingSpace = ts . getLineAndCharacterOfPosition ( sf , referenceNodeInBlock . getStart ( ) ) ;
128148
@@ -151,3 +171,49 @@ export function migrateStandardTsReference(
151171 }
152172 }
153173}
174+
175+ /**
176+ * Determines if a temporary variable should be inserted at the start of a method.
177+ *
178+ * This function performs several checks to ensure it's safe to insert a temporary variable:
179+ * 1. Verifies the recommended node is a method declaration block
180+ * 2. Ensures all references are contained within the method body
181+ * 3. Confirms the reference node is the first statement in the method
182+ * 4. Validates the reference node is an expression statement with an assignment operation
183+ *
184+ * @param references - Object containing the references to be checked
185+ * @param recommendedNode - The node where insertion is being considered (must be a method body block)
186+ * @param referenceNodeInBlock - The specific node within the block where the reference occurs
187+ * @returns `true` if all conditions are met for safe insertion at method start,
188+ * `false` if any condition fails
189+ */
190+ function shouldInsertAtMethodStart (
191+ references : NarrowableTsReferences ,
192+ recommendedNode : ts . Node ,
193+ referenceNodeInBlock : ts . Node ,
194+ ) : boolean {
195+ if ( ! ts . isBlock ( recommendedNode ) || ! ts . isMethodDeclaration ( recommendedNode . parent ) ) {
196+ return false ;
197+ }
198+
199+ const methodBody = recommendedNode ;
200+ const allReferencesInMethod = references . accesses . every ( ( access ) => {
201+ let current : ts . Node | undefined = access ;
202+ while ( current && current !== methodBody ) {
203+ current = current . parent ;
204+ }
205+ return current === methodBody ;
206+ } ) ;
207+
208+ if ( ! allReferencesInMethod ) {
209+ return false ;
210+ }
211+
212+ return (
213+ methodBody . statements . length > 0 &&
214+ ts . isExpressionStatement ( referenceNodeInBlock ) &&
215+ methodBody . statements [ 0 ] === referenceNodeInBlock &&
216+ ts . isBinaryExpression ( referenceNodeInBlock . expression ) &&
217+ referenceNodeInBlock . expression . operatorToken . kind === ts . SyntaxKind . EqualsToken
218+ ) ;
219+ }
0 commit comments