@@ -288,7 +288,7 @@ namespace ts.Completions {
288
288
289
289
switch ( completionData . kind ) {
290
290
case CompletionDataKind . Data :
291
- const response = completionInfoFromData ( sourceFile , host , program , compilerOptions , log , completionData , preferences , formatContext ) ;
291
+ const response = completionInfoFromData ( sourceFile , host , program , compilerOptions , log , completionData , preferences , formatContext , position ) ;
292
292
if ( response ?. isIncomplete ) {
293
293
incompleteCompletionsCache ?. set ( response ) ;
294
294
}
@@ -452,6 +452,7 @@ namespace ts.Completions {
452
452
completionData : CompletionData ,
453
453
preferences : UserPreferences ,
454
454
formatContext : formatting . FormatContext | undefined ,
455
+ position : number
455
456
) : CompletionInfo | undefined {
456
457
const {
457
458
symbols,
@@ -512,7 +513,7 @@ namespace ts.Completions {
512
513
isJsxIdentifierExpected ,
513
514
isRightOfOpenTag ,
514
515
) ;
515
- getJSCompletionEntries ( sourceFile , location . pos , uniqueNames , getEmitScriptTarget ( compilerOptions ) , entries ) ; // TODO: GH#18217
516
+ getJSCompletionEntries ( sourceFile , location . pos , uniqueNames , getEmitScriptTarget ( compilerOptions ) , entries ) ;
516
517
}
517
518
else {
518
519
if ( ! isNewIdentifierLocation && ( ! symbols || symbols . length === 0 ) && keywordFilters === KeywordCompletionFilters . None ) {
@@ -556,6 +557,13 @@ namespace ts.Completions {
556
557
}
557
558
}
558
559
560
+ const entryNames = new Set ( entries . map ( e => e . name ) ) ;
561
+ for ( const keywordEntry of getContextualKeywords ( contextToken , position ) ) {
562
+ if ( ! entryNames . has ( keywordEntry . name ) ) {
563
+ insertSorted ( entries , keywordEntry , compareCompletionEntries , /*allowDuplicates*/ true ) ;
564
+ }
565
+ }
566
+
559
567
for ( const literal of literals ) {
560
568
insertSorted ( entries , createCompletionEntryForLiteral ( sourceFile , preferences , literal ) , compareCompletionEntries , /*allowDuplicates*/ true ) ;
561
569
}
@@ -3630,6 +3638,38 @@ namespace ts.Completions {
3630
3638
return isIdentifier ( node ) ? node . originalKeywordKind || SyntaxKind . Unknown : node . kind ;
3631
3639
}
3632
3640
3641
+ function getContextualKeywords (
3642
+ contextToken : Node | undefined ,
3643
+ position : number ,
3644
+ ) : readonly CompletionEntry [ ] {
3645
+ const entries = [ ] ;
3646
+ /**
3647
+ * An `AssertClause` can come after an import declaration:
3648
+ * import * from "foo" |
3649
+ * import "foo" |
3650
+ * or after a re-export declaration that has a module specifier:
3651
+ * export { foo } from "foo" |
3652
+ * Source: https://tc39.es/proposal-import-assertions/
3653
+ */
3654
+ if ( contextToken ) {
3655
+ const file = contextToken . getSourceFile ( ) ;
3656
+ const parent = contextToken . parent ;
3657
+ const tokenLine = file . getLineAndCharacterOfPosition ( contextToken . end ) . line ;
3658
+ const currentLine = file . getLineAndCharacterOfPosition ( position ) . line ;
3659
+ if ( ( isImportDeclaration ( parent ) || isExportDeclaration ( parent ) && parent . moduleSpecifier )
3660
+ && contextToken === parent . moduleSpecifier
3661
+ && tokenLine === currentLine ) {
3662
+ entries . push ( {
3663
+ name : tokenToString ( SyntaxKind . AssertKeyword ) ! ,
3664
+ kind : ScriptElementKind . keyword ,
3665
+ kindModifiers : ScriptElementKindModifier . none ,
3666
+ sortText : SortText . GlobalsOrKeywords ,
3667
+ } ) ;
3668
+ }
3669
+ }
3670
+ return entries ;
3671
+ }
3672
+
3633
3673
/** Get the corresponding JSDocTag node if the position is in a jsDoc comment */
3634
3674
function getJsDocTagAtPosition ( node : Node , position : number ) : JSDocTag | undefined {
3635
3675
return findAncestor ( node , n =>
0 commit comments