@@ -99,16 +99,27 @@ registerRefactor(refactorName, {
99
99
extractToTypeDefAction . kind ,
100
100
] ,
101
101
getAvailableActions : function getRefactorActionsToExtractType ( context ) : readonly ApplicableRefactorInfo [ ] {
102
- const info = getRangeToExtract ( context , context . triggerReason === "invoked" ) ;
102
+ const { info, affectedTextRange } = getRangeToExtract ( context , context . triggerReason === "invoked" ) ;
103
103
if ( ! info ) return emptyArray ;
104
104
105
105
if ( ! isRefactorErrorInfo ( info ) ) {
106
- return [ {
106
+ const refactorInfo : ApplicableRefactorInfo [ ] = [ {
107
107
name : refactorName ,
108
108
description : getLocaleSpecificMessage ( Diagnostics . Extract_type ) ,
109
109
actions : info . isJS ?
110
110
[ extractToTypeDefAction ] : append ( [ extractToTypeAliasAction ] , info . typeElements && extractToInterfaceAction ) ,
111
111
} ] ;
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
+ } ) ) ;
112
123
}
113
124
114
125
if ( context . preferences . provideRefactorNotApplicableReason ) {
@@ -127,7 +138,7 @@ registerRefactor(refactorName, {
127
138
} ,
128
139
getEditsForAction : function getRefactorEditsToExtractType ( context , actionName ) : RefactorEditInfo {
129
140
const { file } = context ;
130
- const info = getRangeToExtract ( context ) ;
141
+ const { info } = getRangeToExtract ( context ) ;
131
142
Debug . assert ( info && ! isRefactorErrorInfo ( info ) , "Expected to find a range to extract" ) ;
132
143
133
144
const name = getUniqueName ( "NewType" , file ) ;
@@ -171,20 +182,20 @@ interface InterfaceInfo {
171
182
172
183
type ExtractInfo = TypeAliasInfo | InterfaceInfo ;
173
184
174
- function getRangeToExtract ( context : RefactorContext , considerEmptySpans = true ) : ExtractInfo | RefactorErrorInfo | undefined {
185
+ function getRangeToExtract ( context : RefactorContext , considerEmptySpans = true ) : { info : ExtractInfo | RefactorErrorInfo | undefined ; affectedTextRange ?: TextRange ; } {
175
186
const { file, startPosition } = context ;
176
187
const isJS = isSourceFileJS ( file ) ;
177
188
const range = createTextRangeFromSpan ( getRefactorContextSpan ( context ) ) ;
178
189
const isCursorRequest = range . pos === range . end && considerEmptySpans ;
179
190
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 } ;
181
192
182
193
const checker = context . program . getTypeChecker ( ) ;
183
194
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 } ;
185
196
186
197
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 } ;
188
199
189
200
const typeList : TypeNode [ ] = [ ] ;
190
201
if ( ( isUnionTypeNode ( expandedFirstType . parent ) || isIntersectionTypeNode ( expandedFirstType . parent ) ) && range . end > firstType . end ) {
@@ -198,11 +209,11 @@ function getRangeToExtract(context: RefactorContext, considerEmptySpans = true):
198
209
}
199
210
const selection = typeList . length > 1 ? typeList : expandedFirstType ;
200
211
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 } ;
203
214
204
215
const typeElements = flattenTypeLiteralNodeReference ( checker , selection ) ;
205
- return { isJS, selection, enclosingNode, typeParameters, typeElements } ;
216
+ return { info : { isJS, selection, enclosingNode, typeParameters, typeElements } , affectedTextRange } ;
206
217
}
207
218
208
219
function getFirstTypeAt ( file : SourceFile , startPosition : number , range : TextRange , isCursorRequest : boolean ) : Node | undefined {
@@ -260,14 +271,14 @@ function rangeContainsSkipTrivia(r1: TextRange, node: TextRange, file: SourceFil
260
271
return rangeContainsStartEnd ( r1 , skipTrivia ( file . text , node . pos ) , node . end ) ;
261
272
}
262
273
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 ; } {
264
275
const result : TypeParameterDeclaration [ ] = [ ] ;
265
276
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 } ;
267
278
for ( const t of selectionArray ) {
268
- if ( visitor ( t ) ) return undefined ;
279
+ if ( visitor ( t ) ) return { typeParameters : undefined , affectedTextRange : undefined } ;
269
280
}
270
- return result ;
281
+ return { typeParameters : result , affectedTextRange : selectionRange } ;
271
282
272
283
function visitor ( node : Node ) : true | undefined {
273
284
if ( isTypeReferenceNode ( node ) ) {
0 commit comments