@@ -78,7 +78,7 @@ namespace ts.Completions {
78
78
}
79
79
80
80
function completionInfoFromData ( sourceFile : SourceFile , typeChecker : TypeChecker , compilerOptions : CompilerOptions , log : Log , completionData : CompletionData , includeInsertTextCompletions : boolean ) : CompletionInfo {
81
- const { symbols, completionKind, isNewIdentifierLocation, location, propertyAccessToConvert, keywordFilters, symbolToOriginInfoMap, recommendedCompletion } = completionData ;
81
+ const { symbols, completionKind, isNewIdentifierLocation, location, propertyAccessToConvert, keywordFilters, symbolToOriginInfoMap, recommendedCompletion, isJsxInitializer } = completionData ;
82
82
83
83
if ( sourceFile . languageVariant === LanguageVariant . JSX && location && location . parent && isJsxClosingElement ( location . parent ) ) {
84
84
// In the TypeScript JSX element, if such element is not defined. When users query for completion at closing tag,
@@ -99,15 +99,15 @@ namespace ts.Completions {
99
99
const entries : CompletionEntry [ ] = [ ] ;
100
100
101
101
if ( isSourceFileJavaScript ( sourceFile ) ) {
102
- const uniqueNames = getCompletionEntriesFromSymbols ( symbols , entries , location , sourceFile , typeChecker , compilerOptions . target , log , completionKind , includeInsertTextCompletions , propertyAccessToConvert , recommendedCompletion , symbolToOriginInfoMap ) ;
102
+ const uniqueNames = getCompletionEntriesFromSymbols ( symbols , entries , location , sourceFile , typeChecker , compilerOptions . target , log , completionKind , includeInsertTextCompletions , propertyAccessToConvert , isJsxInitializer , recommendedCompletion , symbolToOriginInfoMap ) ;
103
103
getJavaScriptCompletionEntries ( sourceFile , location . pos , uniqueNames , compilerOptions . target , entries ) ;
104
104
}
105
105
else {
106
106
if ( ( ! symbols || symbols . length === 0 ) && keywordFilters === KeywordCompletionFilters . None ) {
107
107
return undefined ;
108
108
}
109
109
110
- getCompletionEntriesFromSymbols ( symbols , entries , location , sourceFile , typeChecker , compilerOptions . target , log , completionKind , includeInsertTextCompletions , propertyAccessToConvert , recommendedCompletion , symbolToOriginInfoMap ) ;
110
+ getCompletionEntriesFromSymbols ( symbols , entries , location , sourceFile , typeChecker , compilerOptions . target , log , completionKind , includeInsertTextCompletions , propertyAccessToConvert , isJsxInitializer , recommendedCompletion , symbolToOriginInfoMap ) ;
111
111
}
112
112
113
113
// TODO add filter for keyword based on type/value/namespace and also location
@@ -167,26 +167,35 @@ namespace ts.Completions {
167
167
origin : SymbolOriginInfo | undefined ,
168
168
recommendedCompletion : Symbol | undefined ,
169
169
propertyAccessToConvert : PropertyAccessExpression | undefined ,
170
+ isJsxInitializer : boolean ,
170
171
includeInsertTextCompletions : boolean ,
171
172
) : CompletionEntry | undefined {
172
173
const info = getCompletionEntryDisplayNameForSymbol ( symbol , target , origin , kind ) ;
173
174
if ( ! info ) {
174
175
return undefined ;
175
176
}
176
177
const { name, needsConvertPropertyAccess } = info ;
177
- if ( needsConvertPropertyAccess && ! includeInsertTextCompletions ) {
178
- return undefined ;
179
- }
180
178
181
179
let insertText : string | undefined ;
182
180
let replacementSpan : TextSpan | undefined ;
183
- if ( origin && origin . type === "this-type" ) {
184
- insertText = needsConvertPropertyAccess ? `this["${ name } "]` : `this.${ name } ` ;
181
+ if ( includeInsertTextCompletions ) {
182
+ if ( origin && origin . type === "this-type" ) {
183
+ insertText = needsConvertPropertyAccess ? `this["${ name } "]` : `this.${ name } ` ;
184
+ }
185
+ else if ( needsConvertPropertyAccess ) {
186
+ // TODO: GH#20619 Use configured quote style
187
+ insertText = `["${ name } "]` ;
188
+ replacementSpan = createTextSpanFromBounds ( findChildOfKind ( propertyAccessToConvert ! , SyntaxKind . DotToken , sourceFile ) ! . getStart ( sourceFile ) , propertyAccessToConvert ! . name . end ) ;
189
+ }
190
+
191
+ if ( isJsxInitializer ) {
192
+ if ( insertText === undefined ) insertText = name ;
193
+ insertText = `{${ insertText } }` ;
194
+ }
185
195
}
186
- else if ( needsConvertPropertyAccess ) {
187
- // TODO: GH#20619 Use configured quote style
188
- insertText = `["${ name } "]` ;
189
- replacementSpan = createTextSpanFromBounds ( findChildOfKind ( propertyAccessToConvert ! , SyntaxKind . DotToken , sourceFile ) ! . getStart ( sourceFile ) , propertyAccessToConvert ! . name . end ) ;
196
+
197
+ if ( insertText !== undefined && ! includeInsertTextCompletions ) {
198
+ return undefined ;
190
199
}
191
200
192
201
// TODO(drosen): Right now we just permit *all* semantic meanings when calling
@@ -235,6 +244,7 @@ namespace ts.Completions {
235
244
kind : CompletionKind ,
236
245
includeInsertTextCompletions ?: boolean ,
237
246
propertyAccessToConvert ?: PropertyAccessExpression | undefined ,
247
+ isJsxInitializer ?: boolean ,
238
248
recommendedCompletion ?: Symbol ,
239
249
symbolToOriginInfoMap ?: SymbolOriginInfoMap ,
240
250
) : Map < true > {
@@ -246,7 +256,7 @@ namespace ts.Completions {
246
256
const uniques = createMap < true > ( ) ;
247
257
for ( const symbol of symbols ) {
248
258
const origin = symbolToOriginInfoMap ? symbolToOriginInfoMap [ getSymbolId ( symbol ) ] : undefined ;
249
- const entry = createCompletionEntry ( symbol , location , sourceFile , typeChecker , target , kind , origin , recommendedCompletion , propertyAccessToConvert , includeInsertTextCompletions ) ;
259
+ const entry = createCompletionEntry ( symbol , location , sourceFile , typeChecker , target , kind , origin , recommendedCompletion , propertyAccessToConvert , isJsxInitializer , includeInsertTextCompletions ) ;
250
260
if ( ! entry ) {
251
261
continue ;
252
262
}
@@ -483,6 +493,7 @@ namespace ts.Completions {
483
493
location : Node ;
484
494
symbolToOriginInfoMap : SymbolOriginInfoMap ;
485
495
previousToken : Node ;
496
+ readonly isJsxInitializer : boolean ;
486
497
}
487
498
function getSymbolCompletionFromEntryId (
488
499
typeChecker : TypeChecker ,
@@ -501,7 +512,7 @@ namespace ts.Completions {
501
512
return { type : "request" , request : completionData } ;
502
513
}
503
514
504
- const { symbols, location, completionKind, symbolToOriginInfoMap, previousToken } = completionData ;
515
+ const { symbols, location, completionKind, symbolToOriginInfoMap, previousToken, isJsxInitializer } = completionData ;
505
516
506
517
// Find the symbol with the matching entry name.
507
518
// We don't need to perform character checks here because we're only comparing the
@@ -510,7 +521,7 @@ namespace ts.Completions {
510
521
return firstDefined < Symbol , SymbolCompletion > ( symbols , ( symbol ) : SymbolCompletion => { // TODO: Shouldn't need return type annotation (GH#12632)
511
522
const origin = symbolToOriginInfoMap [ getSymbolId ( symbol ) ] ;
512
523
const info = getCompletionEntryDisplayNameForSymbol ( symbol , compilerOptions . target , origin , completionKind ) ;
513
- return info && info . name === name && getSourceFromOrigin ( origin ) === source ? { type : "symbol" as "symbol" , symbol, location, symbolToOriginInfoMap, previousToken } : undefined ;
524
+ return info && info . name === name && getSourceFromOrigin ( origin ) === source ? { type : "symbol" as "symbol" , symbol, location, symbolToOriginInfoMap, previousToken, isJsxInitializer } : undefined ;
514
525
} ) || { type : "none" } ;
515
526
}
516
527
@@ -678,6 +689,7 @@ namespace ts.Completions {
678
689
readonly symbolToOriginInfoMap : SymbolOriginInfoMap ;
679
690
readonly recommendedCompletion : Symbol | undefined ;
680
691
readonly previousToken : Node | undefined ;
692
+ readonly isJsxInitializer : boolean ;
681
693
}
682
694
type Request = { readonly kind : CompletionDataKind . JsDocTagName | CompletionDataKind . JsDocTag } | { readonly kind : CompletionDataKind . JsDocParameterName , tag : JSDocParameterTag } ;
683
695
@@ -859,6 +871,7 @@ namespace ts.Completions {
859
871
let isRightOfDot = false ;
860
872
let isRightOfOpenTag = false ;
861
873
let isStartingCloseTag = false ;
874
+ let isJsxInitializer = false ;
862
875
863
876
let location = getTouchingPropertyName ( sourceFile , position , insideJsDocTagTypeExpression ) ; // TODO: GH#15853
864
877
if ( contextToken ) {
@@ -917,6 +930,10 @@ namespace ts.Completions {
917
930
location = contextToken ;
918
931
}
919
932
break ;
933
+
934
+ case SyntaxKind . JsxAttribute :
935
+ isJsxInitializer = previousToken . kind === SyntaxKind . EqualsToken ;
936
+ break ;
920
937
}
921
938
}
922
939
}
@@ -962,7 +979,7 @@ namespace ts.Completions {
962
979
log ( "getCompletionData: Semantic work: " + ( timestamp ( ) - semanticStart ) ) ;
963
980
964
981
const recommendedCompletion = previousToken && getRecommendedCompletion ( previousToken , typeChecker ) ;
965
- return { kind : CompletionDataKind . Data , symbols, completionKind, propertyAccessToConvert, isNewIdentifierLocation, location, keywordFilters, symbolToOriginInfoMap, recommendedCompletion, previousToken } ;
982
+ return { kind : CompletionDataKind . Data , symbols, completionKind, propertyAccessToConvert, isNewIdentifierLocation, location, keywordFilters, symbolToOriginInfoMap, recommendedCompletion, previousToken, isJsxInitializer } ;
966
983
967
984
type JSDocTagWithTypeExpression = JSDocParameterTag | JSDocPropertyTag | JSDocReturnTag | JSDocTypeTag | JSDocTypedefTag ;
968
985
0 commit comments