@@ -3,12 +3,17 @@ import {
33 codefix ,
44 Debug ,
55 fileShouldUseJavaScriptRequire ,
6+ findAncestor ,
67 findIndex ,
78 forEachChild ,
89 formatting ,
10+ getNewLineOrDefaultFromHost ,
911 getQuotePreference ,
12+ getTokenAtPosition ,
1013 isIdentifier ,
1114 Program ,
15+ rangeContainsPosition ,
16+ rangeContainsRange ,
1217 SourceFile ,
1318 Statement ,
1419 SymbolFlags ,
@@ -56,17 +61,16 @@ function pasteEdits(
5661 cancellationToken : CancellationToken ,
5762 changes : textChanges . ChangeTracker ,
5863) {
59- let actualPastedText : string [ ] | undefined ;
64+ let actualPastedText : string | undefined ;
6065 if ( pastedText . length !== pasteLocations . length ) {
61- actualPastedText = pastedText . length === 1 ? pastedText : [ pastedText . join ( "\n" ) ] ;
66+ actualPastedText = pastedText . length === 1 ? pastedText [ 0 ] : pastedText . join ( getNewLineOrDefaultFromHost ( formatContext . host , formatContext . options ) ) ;
6267 }
6368
6469 const statements : Statement [ ] = [ ] ;
65-
6670 let newText = targetFile . text ;
6771 for ( let i = pasteLocations . length - 1 ; i >= 0 ; i -- ) {
6872 const { pos, end } = pasteLocations [ i ] ;
69- newText = actualPastedText ? newText . slice ( 0 , pos ) + actualPastedText [ 0 ] + newText . slice ( end ) : newText . slice ( 0 , pos ) + pastedText [ i ] + newText . slice ( end ) ;
73+ newText = actualPastedText ? newText . slice ( 0 , pos ) + actualPastedText + newText . slice ( end ) : newText . slice ( 0 , pos ) + pastedText [ i ] + newText . slice ( end ) ;
7074 }
7175
7276 let importAdder : codefix . ImportAdder ;
@@ -104,12 +108,46 @@ function pasteEdits(
104108 preferences,
105109 formatContext,
106110 } ;
107- forEachChild ( updatedFile , function cb ( node ) {
108- if ( isIdentifier ( node ) && ! originalProgram ?. getTypeChecker ( ) . resolveName ( node . text , node , SymbolFlags . All , /*excludeGlobals*/ false ) ) {
109- // generate imports
110- importAdder . addImportForUnresolvedIdentifier ( context , node , /*useAutoImportProvider*/ true ) ;
111- }
112- node . forEachChild ( cb ) ;
111+
112+ // `updatedRanges` represent the new ranges that account for the offset changes caused by pasting new text and
113+ // `offset` represents by how much the starting position of `pasteLocations` needs to be changed.
114+ //
115+ // We iterate over each updated range to get the node that wholly encloses the updated range.
116+ // For each child of that node, we checked for unresolved identifiers
117+ // within the updated range and try importing it.
118+ let offset = 0 ;
119+ pasteLocations . forEach ( ( location , i ) => {
120+ const oldTextLength = location . end - location . pos ;
121+ const textToBePasted = actualPastedText ?? pastedText [ i ] ;
122+ const startPos = location . pos + offset ;
123+ const endPos = startPos + textToBePasted . length ;
124+ const range : TextRange = { pos : startPos , end : endPos } ;
125+ offset += textToBePasted . length - oldTextLength ;
126+
127+ const enclosingNode = findAncestor (
128+ getTokenAtPosition ( context . sourceFile , range . pos ) ,
129+ ancestorNode => rangeContainsRange ( ancestorNode , range ) ,
130+ ) ;
131+ if ( ! enclosingNode ) return ;
132+
133+ forEachChild ( enclosingNode , function importUnresolvedIdentifiers ( node ) {
134+ const isImportCandidate = isIdentifier ( node ) &&
135+ rangeContainsPosition ( range , node . getStart ( updatedFile ) ) &&
136+ ! updatedProgram ?. getTypeChecker ( ) . resolveName (
137+ node . text ,
138+ node ,
139+ SymbolFlags . All ,
140+ /*excludeGlobals*/ false ,
141+ ) ;
142+ if ( isImportCandidate ) {
143+ return importAdder . addImportForUnresolvedIdentifier (
144+ context ,
145+ node ,
146+ /*useAutoImportProvider*/ true ,
147+ ) ;
148+ }
149+ node . forEachChild ( importUnresolvedIdentifiers ) ;
150+ } ) ;
113151 } ) ;
114152 }
115153 importAdder . writeFixes ( changes , getQuotePreference ( copiedFrom ? copiedFrom . file : targetFile , preferences ) ) ;
@@ -125,8 +163,7 @@ function pasteEdits(
125163 changes . replaceRangeWithText (
126164 targetFile ,
127165 { pos : paste . pos , end : paste . end } ,
128- actualPastedText ?
129- actualPastedText [ 0 ] : pastedText [ i ] ,
166+ actualPastedText ?? pastedText [ i ] ,
130167 ) ;
131168 } ) ;
132169}
0 commit comments