@@ -99,16 +99,27 @@ registerRefactor(refactorName, {
9999 extractToTypeDefAction . kind ,
100100 ] ,
101101 getAvailableActions : function getRefactorActionsToExtractType ( context ) : readonly ApplicableRefactorInfo [ ] {
102- const info = getRangeToExtract ( context , context . triggerReason === "invoked" ) ;
102+ const { info, affectedTextRange } = getRangeToExtract ( context , context . triggerReason === "invoked" ) ;
103103 if ( ! info ) return emptyArray ;
104104
105105 if ( ! isRefactorErrorInfo ( info ) ) {
106- return [ {
106+ const refactorInfo : ApplicableRefactorInfo [ ] = [ {
107107 name : refactorName ,
108108 description : getLocaleSpecificMessage ( Diagnostics . Extract_type ) ,
109109 actions : info . isJS ?
110110 [ extractToTypeDefAction ] : append ( [ extractToTypeAliasAction ] , info . typeElements && extractToInterfaceAction ) ,
111111 } ] ;
112+ return refactorInfo . map ( info => ( {
113+ ...info ,
114+ actions : info . actions . map ( action => ( {
115+ ...action ,
116+ range : affectedTextRange ? {
117+ start : { line : getLineAndCharacterOfPosition ( context . file , affectedTextRange . pos ) . line , offset : getLineAndCharacterOfPosition ( context . file , affectedTextRange . pos ) . character } ,
118+ end : { line : getLineAndCharacterOfPosition ( context . file , affectedTextRange . end ) . line , offset : getLineAndCharacterOfPosition ( context . file , affectedTextRange . end ) . character } ,
119+ }
120+ : undefined ,
121+ } ) ) ,
122+ } ) ) ;
112123 }
113124
114125 if ( context . preferences . provideRefactorNotApplicableReason ) {
@@ -127,7 +138,7 @@ registerRefactor(refactorName, {
127138 } ,
128139 getEditsForAction : function getRefactorEditsToExtractType ( context , actionName ) : RefactorEditInfo {
129140 const { file } = context ;
130- const info = getRangeToExtract ( context ) ;
141+ const { info } = getRangeToExtract ( context ) ;
131142 Debug . assert ( info && ! isRefactorErrorInfo ( info ) , "Expected to find a range to extract" ) ;
132143
133144 const name = getUniqueName ( "NewType" , file ) ;
@@ -171,20 +182,20 @@ interface InterfaceInfo {
171182
172183type ExtractInfo = TypeAliasInfo | InterfaceInfo ;
173184
174- function getRangeToExtract ( context : RefactorContext , considerEmptySpans = true ) : ExtractInfo | RefactorErrorInfo | undefined {
185+ function getRangeToExtract ( context : RefactorContext , considerEmptySpans = true ) : { info : ExtractInfo | RefactorErrorInfo | undefined ; affectedTextRange ?: TextRange ; } {
175186 const { file, startPosition } = context ;
176187 const isJS = isSourceFileJS ( file ) ;
177188 const range = createTextRangeFromSpan ( getRefactorContextSpan ( context ) ) ;
178189 const isCursorRequest = range . pos === range . end && considerEmptySpans ;
179190 const firstType = getFirstTypeAt ( file , startPosition , range , isCursorRequest ) ;
180- if ( ! firstType || ! isTypeNode ( firstType ) ) return { error : getLocaleSpecificMessage ( Diagnostics . Selection_is_not_a_valid_type_node ) } ;
191+ if ( ! firstType || ! isTypeNode ( firstType ) ) return { info : { error : getLocaleSpecificMessage ( Diagnostics . Selection_is_not_a_valid_type_node ) } , affectedTextRange : undefined } ;
181192
182193 const checker = context . program . getTypeChecker ( ) ;
183194 const enclosingNode = getEnclosingNode ( firstType , isJS ) ;
184- if ( enclosingNode === undefined ) return { error : getLocaleSpecificMessage ( Diagnostics . No_type_could_be_extracted_from_this_type_node ) } ;
195+ if ( enclosingNode === undefined ) return { info : { error : getLocaleSpecificMessage ( Diagnostics . No_type_could_be_extracted_from_this_type_node ) } , affectedTextRange : undefined } ;
185196
186197 const expandedFirstType = getExpandedSelectionNode ( firstType , enclosingNode ) ;
187- if ( ! isTypeNode ( expandedFirstType ) ) return { error : getLocaleSpecificMessage ( Diagnostics . Selection_is_not_a_valid_type_node ) } ;
198+ if ( ! isTypeNode ( expandedFirstType ) ) return { info : { error : getLocaleSpecificMessage ( Diagnostics . Selection_is_not_a_valid_type_node ) } , affectedTextRange : undefined } ;
188199
189200 const typeList : TypeNode [ ] = [ ] ;
190201 if ( ( isUnionTypeNode ( expandedFirstType . parent ) || isIntersectionTypeNode ( expandedFirstType . parent ) ) && range . end > firstType . end ) {
@@ -198,11 +209,11 @@ function getRangeToExtract(context: RefactorContext, considerEmptySpans = true):
198209 }
199210 const selection = typeList . length > 1 ? typeList : expandedFirstType ;
200211
201- const typeParameters = collectTypeParameters ( checker , selection , enclosingNode , file ) ;
202- if ( ! typeParameters ) return { error : getLocaleSpecificMessage ( Diagnostics . No_type_could_be_extracted_from_this_type_node ) } ;
212+ const { typeParameters, affectedTextRange } = collectTypeParameters ( checker , selection , enclosingNode , file ) ;
213+ if ( ! typeParameters ) return { info : { error : getLocaleSpecificMessage ( Diagnostics . No_type_could_be_extracted_from_this_type_node ) } , affectedTextRange : undefined } ;
203214
204215 const typeElements = flattenTypeLiteralNodeReference ( checker , selection ) ;
205- return { isJS, selection, enclosingNode, typeParameters, typeElements } ;
216+ return { info : { isJS, selection, enclosingNode, typeParameters, typeElements } , affectedTextRange } ;
206217}
207218
208219function getFirstTypeAt ( file : SourceFile , startPosition : number , range : TextRange , isCursorRequest : boolean ) : Node | undefined {
@@ -260,14 +271,14 @@ function rangeContainsSkipTrivia(r1: TextRange, node: TextRange, file: SourceFil
260271 return rangeContainsStartEnd ( r1 , skipTrivia ( file . text , node . pos ) , node . end ) ;
261272}
262273
263- function collectTypeParameters ( checker : TypeChecker , selection : TypeNode | TypeNode [ ] , enclosingNode : Node , file : SourceFile ) : TypeParameterDeclaration [ ] | undefined {
274+ function collectTypeParameters ( checker : TypeChecker , selection : TypeNode | TypeNode [ ] , enclosingNode : Node , file : SourceFile ) : { typeParameters : TypeParameterDeclaration [ ] | undefined ; affectedTextRange : TextRange | undefined ; } {
264275 const result : TypeParameterDeclaration [ ] = [ ] ;
265276 const selectionArray = toArray ( selection ) ;
266- const selectionRange = { pos : selectionArray [ 0 ] . pos , end : selectionArray [ selectionArray . length - 1 ] . end } ;
277+ const selectionRange = { pos : selectionArray [ 0 ] . getStart ( file ) , end : selectionArray [ selectionArray . length - 1 ] . end } ;
267278 for ( const t of selectionArray ) {
268- if ( visitor ( t ) ) return undefined ;
279+ if ( visitor ( t ) ) return { typeParameters : undefined , affectedTextRange : undefined } ;
269280 }
270- return result ;
281+ return { typeParameters : result , affectedTextRange : selectionRange } ;
271282
272283 function visitor ( node : Node ) : true | undefined {
273284 if ( isTypeReferenceNode ( node ) ) {
0 commit comments