@@ -1428,6 +1428,9 @@ namespace ts {
1428
1428
// class X {}
1429
1429
export const classElement = "class" ;
1430
1430
1431
+ // var x = class X {}
1432
+ export const localClassElement = "local class" ;
1433
+
1431
1434
// interface Y {}
1432
1435
export const interfaceElement = "interface" ;
1433
1436
@@ -2799,18 +2802,15 @@ namespace ts {
2799
2802
program . getGlobalDiagnostics ( cancellationToken ) ) ;
2800
2803
}
2801
2804
2802
- /// Completion
2803
- function getCompletionEntryDisplayNameForSymbol ( symbol : Symbol , target : ScriptTarget , performCharacterChecks : boolean ) : string {
2804
- let displayName = symbol . getName ( ) ;
2805
- if ( displayName ) {
2806
- // If this is the default export, get the name of the declaration if it exists
2807
- if ( displayName === "default" ) {
2808
- let localSymbol = getLocalSymbolForExportDefault ( symbol ) ;
2809
- if ( localSymbol && localSymbol . name ) {
2810
- displayName = symbol . valueDeclaration . localSymbol . name ;
2811
- }
2812
- }
2805
+ /**
2806
+ * Get the name to be display in completion from a given symbol.
2807
+ *
2808
+ * @return undefined if the name is of external module otherwise a name with striped of any quote
2809
+ */
2810
+ function getCompletionEntryDisplayNameForSymbol ( symbol : Symbol , target : ScriptTarget , performCharacterChecks : boolean , location : Node ) : string {
2811
+ let displayName : string = getDeclaredName ( program . getTypeChecker ( ) , symbol , location ) ;
2813
2812
2813
+ if ( displayName ) {
2814
2814
let firstCharCode = displayName . charCodeAt ( 0 ) ;
2815
2815
// First check of the displayName is not external module; if it is an external module, it is not valid entry
2816
2816
if ( ( symbol . flags & SymbolFlags . Namespace ) && ( firstCharCode === CharacterCodes . singleQuote || firstCharCode === CharacterCodes . doubleQuote ) ) {
@@ -2823,37 +2823,38 @@ namespace ts {
2823
2823
return getCompletionEntryDisplayName ( displayName , target , performCharacterChecks ) ;
2824
2824
}
2825
2825
2826
- function getCompletionEntryDisplayName ( displayName : string , target : ScriptTarget , performCharacterChecks : boolean ) : string {
2827
- if ( ! displayName ) {
2826
+ /**
2827
+ * Get a displayName from a given for completion list, performing any necessary quotes stripping
2828
+ * and checking whether the name is valid identifier name.
2829
+ */
2830
+ function getCompletionEntryDisplayName ( name : string , target : ScriptTarget , performCharacterChecks : boolean ) : string {
2831
+ if ( ! name ) {
2828
2832
return undefined ;
2829
2833
}
2830
2834
2831
- let firstCharCode = displayName . charCodeAt ( 0 ) ;
2832
- if ( displayName . length >= 2 &&
2833
- firstCharCode === displayName . charCodeAt ( displayName . length - 1 ) &&
2834
- ( firstCharCode === CharacterCodes . singleQuote || firstCharCode === CharacterCodes . doubleQuote ) ) {
2835
- // If the user entered name for the symbol was quoted, removing the quotes is not enough, as the name could be an
2836
- // invalid identifier name. We need to check if whatever was inside the quotes is actually a valid identifier name.
2837
- displayName = displayName . substring ( 1 , displayName . length - 1 ) ;
2838
- }
2835
+ name = stripQuotes ( name ) ;
2839
2836
2840
- if ( ! displayName ) {
2837
+ if ( ! name ) {
2841
2838
return undefined ;
2842
2839
}
2843
2840
2841
+ // If the user entered name for the symbol was quoted, removing the quotes is not enough, as the name could be an
2842
+ // invalid identifier name. We need to check if whatever was inside the quotes is actually a valid identifier name.
2843
+ // e.g "b a" is valid quoted name but when we strip off the quotes, it is invalid.
2844
+ // We, thus, need to check if whatever was inside the quotes is actually a valid identifier name.
2844
2845
if ( performCharacterChecks ) {
2845
- if ( ! isIdentifierStart ( displayName . charCodeAt ( 0 ) , target ) ) {
2846
+ if ( ! isIdentifierStart ( name . charCodeAt ( 0 ) , target ) ) {
2846
2847
return undefined ;
2847
2848
}
2848
2849
2849
- for ( let i = 1 , n = displayName . length ; i < n ; i ++ ) {
2850
- if ( ! isIdentifierPart ( displayName . charCodeAt ( i ) , target ) ) {
2850
+ for ( let i = 1 , n = name . length ; i < n ; i ++ ) {
2851
+ if ( ! isIdentifierPart ( name . charCodeAt ( i ) , target ) ) {
2851
2852
return undefined ;
2852
2853
}
2853
2854
}
2854
2855
}
2855
2856
2856
- return unescapeIdentifier ( displayName ) ;
2857
+ return name ;
2857
2858
}
2858
2859
2859
2860
function getCompletionData ( fileName : string , position : number ) {
@@ -3607,7 +3608,7 @@ namespace ts {
3607
3608
// Try to get a valid display name for this symbol, if we could not find one, then ignore it.
3608
3609
// We would like to only show things that can be added after a dot, so for instance numeric properties can
3609
3610
// not be accessed with a dot (a.1 <- invalid)
3610
- let displayName = getCompletionEntryDisplayNameForSymbol ( symbol , program . getCompilerOptions ( ) . target , /*performCharacterChecks:*/ true ) ;
3611
+ let displayName = getCompletionEntryDisplayNameForSymbol ( symbol , program . getCompilerOptions ( ) . target , /*performCharacterChecks:*/ true , location ) ;
3611
3612
if ( ! displayName ) {
3612
3613
return undefined ;
3613
3614
}
@@ -3664,7 +3665,7 @@ namespace ts {
3664
3665
// We don't need to perform character checks here because we're only comparing the
3665
3666
// name against 'entryName' (which is known to be good), not building a new
3666
3667
// completion entry.
3667
- let symbol = forEach ( symbols , s => getCompletionEntryDisplayNameForSymbol ( s , target , /*performCharacterChecks:*/ false ) === entryName ? s : undefined ) ;
3668
+ let symbol = forEach ( symbols , s => getCompletionEntryDisplayNameForSymbol ( s , target , /*performCharacterChecks:*/ false , location ) === entryName ? s : undefined ) ;
3668
3669
3669
3670
if ( symbol ) {
3670
3671
let { displayParts, documentation, symbolKind } = getSymbolDisplayPartsDocumentationAndSymbolKind ( symbol , getValidSourceFile ( fileName ) , location , location , SemanticMeaning . All ) ;
@@ -3697,7 +3698,8 @@ namespace ts {
3697
3698
function getSymbolKind ( symbol : Symbol , location : Node ) : string {
3698
3699
let flags = symbol . getFlags ( ) ;
3699
3700
3700
- if ( flags & SymbolFlags . Class ) return ScriptElementKind . classElement ;
3701
+ if ( flags & SymbolFlags . Class ) return getDeclarationOfKind ( symbol , SyntaxKind . ClassExpression ) ?
3702
+ ScriptElementKind . localClassElement : ScriptElementKind . classElement ;
3701
3703
if ( flags & SymbolFlags . Enum ) return ScriptElementKind . enumElement ;
3702
3704
if ( flags & SymbolFlags . TypeAlias ) return ScriptElementKind . typeElement ;
3703
3705
if ( flags & SymbolFlags . Interface ) return ScriptElementKind . interfaceElement ;
@@ -3906,7 +3908,16 @@ namespace ts {
3906
3908
}
3907
3909
}
3908
3910
if ( symbolFlags & SymbolFlags . Class && ! hasAddedSymbolInfo ) {
3909
- displayParts . push ( keywordPart ( SyntaxKind . ClassKeyword ) ) ;
3911
+ if ( getDeclarationOfKind ( symbol , SyntaxKind . ClassExpression ) ) {
3912
+ // Special case for class expressions because we would like to indicate that
3913
+ // the class name is local to the class body (similar to function expression)
3914
+ // (local class) class <className>
3915
+ pushTypePart ( ScriptElementKind . localClassElement ) ;
3916
+ }
3917
+ else {
3918
+ // Class declaration has name which is not local.
3919
+ displayParts . push ( keywordPart ( SyntaxKind . ClassKeyword ) ) ;
3920
+ }
3910
3921
displayParts . push ( spacePart ( ) ) ;
3911
3922
addFullSymbolName ( symbol ) ;
3912
3923
writeTypeParametersOfSymbol ( symbol , sourceFile ) ;
@@ -5112,7 +5123,7 @@ namespace ts {
5112
5123
5113
5124
// Get the text to search for.
5114
5125
// Note: if this is an external module symbol, the name doesn't include quotes.
5115
- let declaredName = getDeclaredName ( typeChecker , symbol , node ) ;
5126
+ let declaredName = stripQuotes ( getDeclaredName ( typeChecker , symbol , node ) ) ;
5116
5127
5117
5128
// Try to get the smallest valid scope that we can limit our search to;
5118
5129
// otherwise we'll need to search globally (i.e. include each file).
@@ -5189,10 +5200,10 @@ namespace ts {
5189
5200
* a reference to a symbol can occur anywhere.
5190
5201
*/
5191
5202
function getSymbolScope ( symbol : Symbol ) : Node {
5192
- // If this is the symbol of a function expression, then named references
5193
- // are limited to its own scope.
5203
+ // If this is the symbol of a named function expression or named class expression,
5204
+ // then named references are limited to its own scope.
5194
5205
let valueDeclaration = symbol . valueDeclaration ;
5195
- if ( valueDeclaration && valueDeclaration . kind === SyntaxKind . FunctionExpression ) {
5206
+ if ( valueDeclaration && ( valueDeclaration . kind === SyntaxKind . FunctionExpression || valueDeclaration . kind === SyntaxKind . ClassExpression ) ) {
5196
5207
return valueDeclaration ;
5197
5208
}
5198
5209
@@ -6863,7 +6874,7 @@ namespace ts {
6863
6874
}
6864
6875
}
6865
6876
6866
- let displayName = getDeclaredName ( typeChecker , symbol , node ) ;
6877
+ let displayName = stripQuotes ( getDeclaredName ( typeChecker , symbol , node ) ) ;
6867
6878
let kind = getSymbolKind ( symbol , node ) ;
6868
6879
if ( kind ) {
6869
6880
return {
0 commit comments