@@ -890,6 +890,114 @@ namespace ts {
890
890
return isTemplateLiteralKind ( token . kind ) && position > token . getStart ( sourceFile ) ;
891
891
}
892
892
893
+ export function findPrecedingMatchingToken ( token : Node , matchingTokenKind : SyntaxKind , sourceFile : SourceFile ) {
894
+ const tokenKind = token . kind ;
895
+ let remainingMatchingTokens = 0 ;
896
+ while ( true ) {
897
+ token = findPrecedingToken ( token . getFullStart ( ) , sourceFile ) ;
898
+ if ( ! token ) {
899
+ return undefined ;
900
+ }
901
+
902
+ if ( token . kind === matchingTokenKind ) {
903
+ if ( remainingMatchingTokens === 0 ) {
904
+ return token ;
905
+ }
906
+
907
+ remainingMatchingTokens -- ;
908
+ }
909
+ else if ( token . kind === tokenKind ) {
910
+ remainingMatchingTokens ++ ;
911
+ }
912
+ }
913
+ }
914
+
915
+ export function isPossiblyTypeArgumentPosition ( token : Node , sourceFile : SourceFile ) {
916
+ // This function determines if the node could be type argument position
917
+ // Since during editing, when type argument list is not complete,
918
+ // the tree could be of any shape depending on the tokens parsed before current node,
919
+ // scanning of the previous identifier followed by "<" before current node would give us better result
920
+ // Note that we also balance out the already provided type arguments, arrays, object literals while doing so
921
+ let remainingLessThanTokens = 0 ;
922
+ while ( token ) {
923
+ switch ( token . kind ) {
924
+ case SyntaxKind . LessThanToken :
925
+ // Found the beginning of the generic argument expression
926
+ token = findPrecedingToken ( token . getFullStart ( ) , sourceFile ) ;
927
+ const tokenIsIdentifier = token && isIdentifier ( token ) ;
928
+ if ( ! remainingLessThanTokens || ! tokenIsIdentifier ) {
929
+ return tokenIsIdentifier ;
930
+ }
931
+ remainingLessThanTokens -- ;
932
+ break ;
933
+
934
+ case SyntaxKind . GreaterThanGreaterThanGreaterThanToken :
935
+ remainingLessThanTokens = + 3 ;
936
+ break ;
937
+
938
+ case SyntaxKind . GreaterThanGreaterThanToken :
939
+ remainingLessThanTokens = + 2 ;
940
+ break ;
941
+
942
+ case SyntaxKind . GreaterThanToken :
943
+ remainingLessThanTokens ++ ;
944
+ break ;
945
+
946
+ case SyntaxKind . CloseBraceToken :
947
+ // This can be object type, skip untill we find the matching open brace token
948
+ // Skip untill the matching open brace token
949
+ token = findPrecedingMatchingToken ( token , SyntaxKind . OpenBraceToken , sourceFile ) ;
950
+ if ( ! token ) return false ;
951
+ break ;
952
+
953
+ case SyntaxKind . CloseParenToken :
954
+ // This can be object type, skip untill we find the matching open brace token
955
+ // Skip untill the matching open brace token
956
+ token = findPrecedingMatchingToken ( token , SyntaxKind . OpenParenToken , sourceFile ) ;
957
+ if ( ! token ) return false ;
958
+ break ;
959
+
960
+ case SyntaxKind . CloseBracketToken :
961
+ // This can be object type, skip untill we find the matching open brace token
962
+ // Skip untill the matching open brace token
963
+ token = findPrecedingMatchingToken ( token , SyntaxKind . OpenBracketToken , sourceFile ) ;
964
+ if ( ! token ) return false ;
965
+ break ;
966
+
967
+ // Valid tokens in a type name. Skip.
968
+ case SyntaxKind . CommaToken :
969
+ case SyntaxKind . EqualsGreaterThanToken :
970
+
971
+ case SyntaxKind . Identifier :
972
+ case SyntaxKind . StringLiteral :
973
+ case SyntaxKind . NumericLiteral :
974
+ case SyntaxKind . TrueKeyword :
975
+ case SyntaxKind . FalseKeyword :
976
+
977
+ case SyntaxKind . TypeOfKeyword :
978
+ case SyntaxKind . ExtendsKeyword :
979
+ case SyntaxKind . KeyOfKeyword :
980
+ case SyntaxKind . DotToken :
981
+ case SyntaxKind . BarToken :
982
+ case SyntaxKind . QuestionToken :
983
+ case SyntaxKind . ColonToken :
984
+ break ;
985
+
986
+ default :
987
+ if ( isTypeNode ( token ) ) {
988
+ break ;
989
+ }
990
+
991
+ // Invalid token in type
992
+ return false ;
993
+ }
994
+
995
+ token = findPrecedingToken ( token . getFullStart ( ) , sourceFile ) ;
996
+ }
997
+
998
+ return false ;
999
+ }
1000
+
893
1001
/**
894
1002
* Returns true if the cursor at position in sourceFile is within a comment.
895
1003
*
0 commit comments