1
1
import {
2
2
__String ,
3
+ ArrayTypeNode ,
3
4
ArrowFunction ,
4
5
CallExpression ,
6
+ ConditionalTypeNode ,
5
7
createPrinterWithRemoveComments ,
6
8
createTextSpanFromNode ,
7
9
Debug ,
@@ -23,10 +25,14 @@ import {
23
25
getLeadingCommentRanges ,
24
26
hasContextSensitiveParameters ,
25
27
Identifier ,
28
+ idText ,
29
+ ImportTypeNode ,
30
+ IndexedAccessTypeNode ,
26
31
InlayHint ,
27
32
InlayHintDisplayPart ,
28
33
InlayHintKind ,
29
34
InlayHintsContext ,
35
+ IntersectionTypeNode ,
30
36
isArrowFunction ,
31
37
isAssertionExpression ,
32
38
isBindingPattern ,
@@ -53,13 +59,18 @@ import {
53
59
isVarConst ,
54
60
isVariableDeclaration ,
55
61
MethodDeclaration ,
62
+ NamedTupleMember ,
56
63
NewExpression ,
57
64
Node ,
65
+ NodeArray ,
58
66
NodeBuilderFlags ,
67
+ OptionalTypeNode ,
59
68
ParameterDeclaration ,
60
69
ParenthesizedTypeNode ,
61
70
PrefixUnaryExpression ,
62
71
PropertyDeclaration ,
72
+ QualifiedName ,
73
+ RestTypeNode ,
63
74
Signature ,
64
75
skipParentheses ,
65
76
some ,
@@ -69,11 +80,17 @@ import {
69
80
SyntaxKind ,
70
81
textSpanIntersectsWith ,
71
82
tokenToString ,
83
+ TupleTypeNode ,
72
84
TupleTypeReference ,
73
85
Type ,
74
86
TypeFormatFlags ,
75
87
TypeNode ,
88
+ TypeOperatorNode ,
89
+ TypePredicateNode ,
90
+ TypeQueryNode ,
91
+ TypeReferenceNode ,
76
92
unescapeLeadingUnderscores ,
93
+ UnionTypeNode ,
77
94
UserPreferences ,
78
95
usingSingleLineStringWriter ,
79
96
VariableDeclaration ,
@@ -162,7 +179,7 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] {
162
179
function addParameterHints ( text : string , parameter : Identifier , position : number , isFirstVariadicArgument : boolean , sourceFile : SourceFile | undefined ) {
163
180
let hintText : string | InlayHintDisplayPart [ ] = `${ isFirstVariadicArgument ? "..." : "" } ${ text } ` ;
164
181
if ( shouldUseInteractiveInlayHints ( preferences ) ) {
165
- hintText = [ getNodeDisplayPart ( hintText , parameter , sourceFile ! ) , { text : ":" } ] ;
182
+ hintText = [ getNodeDisplayPart ( hintText , parameter , sourceFile ) , { text : ":" } ] ;
166
183
}
167
184
else {
168
185
hintText += ":" ;
@@ -446,13 +463,12 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] {
446
463
447
464
const parts : InlayHintDisplayPart [ ] = [ ] ;
448
465
visitor ( typeNode ) ;
449
- function visitor ( node : TypeNode ) : true | undefined {
466
+ function visitor ( node : Node ) {
450
467
if ( ! node ) {
451
468
return ;
452
469
}
453
470
454
471
switch ( node . kind ) {
455
- // Keyword types:
456
472
case SyntaxKind . AnyKeyword :
457
473
case SyntaxKind . BigIntKeyword :
458
474
case SyntaxKind . BooleanKeyword :
@@ -465,18 +481,186 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] {
465
481
case SyntaxKind . UndefinedKeyword :
466
482
case SyntaxKind . UnknownKeyword :
467
483
case SyntaxKind . VoidKeyword :
468
- parts . push ( { text : tokenToString ( node . kind ) } ) ;
484
+ case SyntaxKind . ThisType :
485
+ parts . push ( { text : tokenToString ( node . kind ) ! } ) ;
486
+ break ;
487
+ case SyntaxKind . Identifier :
488
+ const identifier = node as Identifier ;
489
+ parts . push ( getNodeDisplayPart ( idText ( identifier ) , identifier ) ) ;
490
+ break ;
491
+ case SyntaxKind . QualifiedName :
492
+ const qualifiedName = node as QualifiedName ;
493
+ visitor ( qualifiedName . left ) ;
494
+ parts . push ( { text : "." } ) ;
495
+ visitor ( qualifiedName . right ) ;
496
+ break ;
497
+ case SyntaxKind . TypePredicate :
498
+ const predicate = node as TypePredicateNode ;
499
+ if ( predicate . assertsModifier ) {
500
+ parts . push ( { text : "asserts " } ) ;
501
+ }
502
+ visitor ( predicate . parameterName ) ;
503
+ if ( predicate . type ) {
504
+ parts . push ( { text : " is " } ) ;
505
+ visitor ( predicate . type ) ;
506
+ }
507
+ break ;
508
+ case SyntaxKind . TypeReference :
509
+ const typeReference = node as TypeReferenceNode ;
510
+ visitor ( typeReference . typeName ) ;
511
+ if ( typeReference . typeArguments ) {
512
+ parts . push ( { text : "<" } ) ;
513
+ visitList ( typeReference . typeArguments , "," ) ;
514
+ parts . push ( { text : ">" } ) ;
515
+ }
516
+ break ;
517
+ case SyntaxKind . FunctionType :
518
+ // TODO: Handle this case.
519
+ break ;
520
+ case SyntaxKind . ConstructorType :
521
+ // TODO: Handle this case.
522
+ break ;
523
+ case SyntaxKind . TypeQuery :
524
+ const typeQuery = node as TypeQueryNode ;
525
+ parts . push ( { text : "typeof " } ) ;
526
+ visitor ( typeQuery . exprName ) ;
527
+ if ( typeQuery . typeArguments ) {
528
+ parts . push ( { text : "<" } ) ;
529
+ visitList ( typeQuery . typeArguments , "," ) ;
530
+ parts . push ( { text : ">" } ) ;
531
+ }
532
+ break ;
533
+ case SyntaxKind . TypeLiteral :
534
+ // TODO: Handle this case.
535
+ break ;
536
+ case SyntaxKind . ArrayType :
537
+ visitor ( ( node as ArrayTypeNode ) . elementType ) ;
538
+ parts . push ( { text : "[]" } ) ;
539
+ break ;
540
+ case SyntaxKind . TupleType :
541
+ parts . push ( { text : "[" } ) ;
542
+ visitList ( ( node as TupleTypeNode ) . elements , "," ) ;
543
+ parts . push ( { text : "]" } ) ;
544
+ break ;
545
+ case SyntaxKind . NamedTupleMember :
546
+ const member = node as NamedTupleMember ;
547
+ if ( member . dotDotDotToken ) {
548
+ parts . push ( { text : "..." } ) ;
549
+ }
550
+ visitor ( member . name ) ;
551
+ if ( member . questionToken ) {
552
+ parts . push ( { text : "?" } ) ;
553
+ }
554
+ parts . push ( { text : ": " } ) ;
555
+ visitor ( member . type ) ;
556
+ break ;
557
+ case SyntaxKind . OptionalType :
558
+ visitor ( ( node as OptionalTypeNode ) . type ) ;
559
+ parts . push ( { text : "?" } ) ;
560
+ break ;
561
+ case SyntaxKind . RestType :
562
+ parts . push ( { text : "..." } ) ;
563
+ visitor ( ( node as RestTypeNode ) . type ) ;
564
+ break ;
565
+ case SyntaxKind . UnionType :
566
+ visitList ( ( node as UnionTypeNode ) . types , "|" ) ;
567
+ break ;
568
+ case SyntaxKind . IntersectionType :
569
+ visitList ( ( node as IntersectionTypeNode ) . types , "&" ) ;
570
+ break ;
571
+ case SyntaxKind . ConditionalType :
572
+ const conditionalType = node as ConditionalTypeNode ;
573
+ visitor ( conditionalType . checkType ) ;
574
+ parts . push ( { text : " extends " } ) ;
575
+ visitor ( conditionalType . extendsType ) ;
576
+ parts . push ( { text : " ? " } ) ;
577
+ visitor ( conditionalType . trueType ) ;
578
+ parts . push ( { text : " : " } ) ;
579
+ visitor ( conditionalType . falseType ) ;
580
+ break ;
581
+ case SyntaxKind . InferType :
582
+ // TODO: Handle this case.
469
583
break ;
470
584
case SyntaxKind . ParenthesizedType :
471
585
parts . push ( { text : "(" } ) ;
472
586
visitor ( ( node as ParenthesizedTypeNode ) . type ) ;
473
587
parts . push ( { text : ")" } ) ;
474
588
break ;
589
+ case SyntaxKind . TypeOperator :
590
+ const typeOperator = node as TypeOperatorNode ;
591
+ parts . push ( { text : `${ tokenToString ( typeOperator . operator ) } ` } ) ;
592
+ visitor ( typeOperator . type ) ;
593
+ break ;
594
+ case SyntaxKind . IndexedAccessType :
595
+ const indexedAccess = node as IndexedAccessTypeNode ;
596
+ visitor ( indexedAccess . objectType ) ;
597
+ parts . push ( { text : "[" } ) ;
598
+ visitor ( indexedAccess . indexType ) ;
599
+ parts . push ( { text : "]" } ) ;
600
+ break ;
601
+ case SyntaxKind . MappedType :
602
+ // TODO: Handle this case.
603
+ break ;
604
+ case SyntaxKind . LiteralType :
605
+ // TODO: Handle this case.
606
+ break ;
607
+ case SyntaxKind . TemplateLiteralType :
608
+ // TODO: Handle this case.
609
+ break ;
610
+ case SyntaxKind . TemplateLiteralTypeSpan :
611
+ // TODO: Handle this case.
612
+ break ;
613
+ case SyntaxKind . ImportType :
614
+ const importType = node as ImportTypeNode ;
615
+ if ( importType . isTypeOf ) {
616
+ parts . push ( { text : "typeof " } ) ;
617
+ }
618
+ parts . push ( { text : "import(" } ) ;
619
+ visitor ( importType . argument ) ;
620
+ if ( importType . assertions ) {
621
+ parts . push ( { text : ", { assert: " } ) ;
622
+ // TODO: Visit assert clause entries.
623
+ parts . push ( { text : " }" } ) ;
624
+ }
625
+ parts . push ( { text : ")" } ) ;
626
+ if ( importType . qualifier ) {
627
+ parts . push ( { text : "." } ) ;
628
+ visitor ( importType . qualifier ) ;
629
+ }
630
+ if ( importType . typeArguments ) {
631
+ parts . push ( { text : "<" } ) ;
632
+ visitList ( importType . typeArguments , "," ) ;
633
+ parts . push ( { text : ">" } ) ;
634
+ }
635
+ break ;
636
+ case SyntaxKind . ExpressionWithTypeArguments :
637
+ // TODO: Handle this case.
638
+ break ;
639
+ // TODO: I _think_ that we don't display inlay hints in JSDocs,
640
+ // so I shouldn't worry about these cases (?).
641
+ // case SyntaxKind.JSDocTypeExpression:
642
+ // case SyntaxKind.JSDocAllType:
643
+ // case SyntaxKind.JSDocUnknownType:
644
+ // case SyntaxKind.JSDocNonNullableType:
645
+ // case SyntaxKind.JSDocNullableType:
646
+ // case SyntaxKind.JSDocOptionalType:
647
+ // case SyntaxKind.JSDocFunctionType:
648
+ // case SyntaxKind.JSDocVariadicType:
649
+ // case SyntaxKind.JSDocNamepathType:
650
+ // case SyntaxKind.JSDocSignature:
651
+ // case SyntaxKind.JSDocTypeLiteral:
475
652
default :
476
- // TODO: Make this unreachable when I consider all cases.
477
- return undefined ;
653
+ Debug . fail ( "Type node does not support inlay hints." ) ;
478
654
}
479
655
}
656
+ function visitList ( nodes : NodeArray < TypeNode > , separator : string ) {
657
+ nodes . forEach ( ( node , index ) => {
658
+ if ( index > 0 ) {
659
+ parts . push ( { text : `${ separator } ` } ) ;
660
+ }
661
+ visitor ( node ) ;
662
+ } ) ;
663
+ }
480
664
481
665
return parts ;
482
666
}
@@ -493,7 +677,7 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] {
493
677
return true ;
494
678
}
495
679
496
- function getNodeDisplayPart ( text : string , node : Node , sourceFile : SourceFile ) : InlayHintDisplayPart {
680
+ function getNodeDisplayPart ( text : string , node : Node , sourceFile : SourceFile = node . getSourceFile ( ) ) : InlayHintDisplayPart {
497
681
return {
498
682
text,
499
683
span : createTextSpanFromNode ( node , sourceFile ) ,
0 commit comments