44namespace ts . Completions {
55 export type Log = ( message : string ) => void ;
66
7- interface SymbolOriginInfo {
7+ type SymbolOriginInfo = { type : "this-type" } | SymbolOriginInfoExport ;
8+ interface SymbolOriginInfoExport {
9+ type : "export" ;
810 moduleSymbol : Symbol ;
911 isDefaultExport : boolean ;
1012 }
@@ -170,11 +172,21 @@ namespace ts.Completions {
170172 return undefined ;
171173 }
172174 const { name, needsConvertPropertyAccess } = info ;
173- Debug . assert ( ! ( needsConvertPropertyAccess && ! propertyAccessToConvert ) ) ;
174175 if ( needsConvertPropertyAccess && ! includeInsertTextCompletions ) {
175176 return undefined ;
176177 }
177178
179+ let insertText : string | undefined ;
180+ let replacementSpan : TextSpan | undefined ;
181+ if ( kind === CompletionKind . Global && origin && origin . type === "this-type" ) {
182+ insertText = needsConvertPropertyAccess ? `this["${ name } "]` : `this.${ name } ` ;
183+ }
184+ else if ( needsConvertPropertyAccess ) {
185+ // TODO: GH#20619 Use configured quote style
186+ insertText = `["${ name } "]` ;
187+ replacementSpan = createTextSpanFromBounds ( findChildOfKind ( propertyAccessToConvert ! , SyntaxKind . DotToken , sourceFile ) ! . getStart ( sourceFile ) , propertyAccessToConvert ! . name . end ) ;
188+ }
189+
178190 // TODO(drosen): Right now we just permit *all* semantic meanings when calling
179191 // 'getSymbolKind' which is permissible given that it is backwards compatible; but
180192 // really we should consider passing the meaning for the node so that we don't report
@@ -189,13 +201,10 @@ namespace ts.Completions {
189201 kindModifiers : SymbolDisplay . getSymbolModifiers ( symbol ) ,
190202 sortText : "0" ,
191203 source : getSourceFromOrigin ( origin ) ,
192- // TODO: GH#20619 Use configured quote style
193- insertText : needsConvertPropertyAccess ? `["${ name } "]` : undefined ,
194- replacementSpan : needsConvertPropertyAccess
195- ? createTextSpanFromBounds ( findChildOfKind ( propertyAccessToConvert , SyntaxKind . DotToken , sourceFile ) ! . getStart ( sourceFile ) , propertyAccessToConvert . name . end )
196- : undefined ,
197- hasAction : trueOrUndefined ( needsConvertPropertyAccess || origin !== undefined ) ,
204+ hasAction : trueOrUndefined ( ! ! origin && origin . type === "export" ) ,
198205 isRecommended : trueOrUndefined ( isRecommendedCompletionMatch ( symbol , recommendedCompletion , typeChecker ) ) ,
206+ insertText,
207+ replacementSpan,
199208 } ;
200209 }
201210
@@ -210,7 +219,7 @@ namespace ts.Completions {
210219 }
211220
212221 function getSourceFromOrigin ( origin : SymbolOriginInfo | undefined ) : string | undefined {
213- return origin && stripQuotes ( origin . moduleSymbol . name ) ;
222+ return origin && origin . type === "export" ? stripQuotes ( origin . moduleSymbol . name ) : undefined ;
214223 }
215224
216225 function getCompletionEntriesFromSymbols (
@@ -504,7 +513,7 @@ namespace ts.Completions {
504513 }
505514
506515 function getSymbolName ( symbol : Symbol , origin : SymbolOriginInfo | undefined , target : ScriptTarget ) : string {
507- return origin && origin . isDefaultExport && symbol . escapedName === InternalSymbolName . Default
516+ return origin && origin . type === "export" && origin . isDefaultExport && symbol . escapedName === InternalSymbolName . Default
508517 // Name of "export default foo;" is "foo". Name of "export default 0" is the filename converted to camelCase.
509518 ? firstDefined ( symbol . declarations , d => isExportAssignment ( d ) && isIdentifier ( d . expression ) ? d . expression . text : undefined )
510519 || codefix . moduleSymbolToValidIdentifier ( origin . moduleSymbol , target )
@@ -590,13 +599,13 @@ namespace ts.Completions {
590599 allSourceFiles : ReadonlyArray < SourceFile > ,
591600 ) : CodeActionsAndSourceDisplay {
592601 const symbolOriginInfo = symbolToOriginInfoMap [ getSymbolId ( symbol ) ] ;
593- return symbolOriginInfo
602+ return symbolOriginInfo && symbolOriginInfo . type === "export"
594603 ? getCodeActionsAndSourceDisplayForImport ( symbolOriginInfo , symbol , program , checker , host , compilerOptions , sourceFile , previousToken , formatContext , getCanonicalFileName , allSourceFiles )
595604 : { codeActions : undefined , sourceDisplay : undefined } ;
596605 }
597606
598607 function getCodeActionsAndSourceDisplayForImport (
599- symbolOriginInfo : SymbolOriginInfo ,
608+ symbolOriginInfo : SymbolOriginInfoExport ,
600609 symbol : Symbol ,
601610 program : Program ,
602611 checker : TypeChecker ,
@@ -1117,6 +1126,18 @@ namespace ts.Completions {
11171126 const symbolMeanings = SymbolFlags . Type | SymbolFlags . Value | SymbolFlags . Namespace | SymbolFlags . Alias ;
11181127
11191128 symbols = typeChecker . getSymbolsInScope ( scopeNode , symbolMeanings ) ;
1129+
1130+ // Need to insert 'this.' before properties of `this` type, so only do that if `includeInsertTextCompletions`
1131+ if ( options . includeInsertTextCompletions && scopeNode . kind !== SyntaxKind . SourceFile ) {
1132+ const thisType = typeChecker . tryGetThisTypeAt ( scopeNode ) ;
1133+ if ( thisType ) {
1134+ for ( const symbol of getPropertiesForCompletion ( thisType , typeChecker , /*isForAccess*/ true ) ) {
1135+ symbolToOriginInfoMap [ getSymbolId ( symbol ) ] = { type : "this-type" } ;
1136+ symbols . push ( symbol ) ;
1137+ }
1138+ }
1139+ }
1140+
11201141 if ( options . includeExternalModuleExports ) {
11211142 getSymbolsFromOtherSourceFileExports ( symbols , previousToken && isIdentifier ( previousToken ) ? previousToken . text : "" , target ) ;
11221143 }
@@ -1230,10 +1251,10 @@ namespace ts.Completions {
12301251 symbol = getLocalSymbolForExportDefault ( symbol ) || symbol ;
12311252 }
12321253
1233- const origin : SymbolOriginInfo = { moduleSymbol, isDefaultExport } ;
1254+ const origin : SymbolOriginInfo = { type : "export" , moduleSymbol, isDefaultExport } ;
12341255 if ( stringContainsCharactersInOrder ( getSymbolName ( symbol , origin , target ) . toLowerCase ( ) , tokenTextLowerCase ) ) {
12351256 symbols . push ( symbol ) ;
1236- symbolToOriginInfoMap [ getSymbolId ( symbol ) ] = { moduleSymbol , isDefaultExport } ;
1257+ symbolToOriginInfoMap [ getSymbolId ( symbol ) ] = origin ;
12371258 }
12381259 }
12391260 } ) ;
@@ -2072,13 +2093,13 @@ namespace ts.Completions {
20722093 if ( isIdentifierText ( name , target ) ) return validIdentiferResult ;
20732094 switch ( kind ) {
20742095 case CompletionKind . None :
2075- case CompletionKind . Global :
20762096 case CompletionKind . MemberLike :
20772097 return undefined ;
20782098 case CompletionKind . ObjectPropertyDeclaration :
20792099 // TODO: GH#18169
20802100 return { name : JSON . stringify ( name ) , needsConvertPropertyAccess : false } ;
20812101 case CompletionKind . PropertyAccess :
2102+ case CompletionKind . Global :
20822103 // Don't add a completion for a name starting with a space. See https://github.com/Microsoft/TypeScript/pull/20547
20832104 return name . charCodeAt ( 0 ) === CharacterCodes . space ? undefined : { name, needsConvertPropertyAccess : true } ;
20842105 case CompletionKind . String :
0 commit comments