@@ -3028,17 +3028,17 @@ namespace ts {
3028
3028
3029
3029
function tryGetGlobalSymbols ( ) : boolean {
3030
3030
let objectLikeContainer : ObjectLiteralExpression | BindingPattern ;
3031
- let importClause : ImportClause ;
3031
+ let namedImportsOrExports : NamedImportsOrExports ;
3032
3032
let jsxContainer : JsxOpeningLikeElement ;
3033
3033
3034
3034
if ( objectLikeContainer = tryGetObjectLikeCompletionContainer ( contextToken ) ) {
3035
3035
return tryGetObjectLikeCompletionSymbols ( objectLikeContainer ) ;
3036
3036
}
3037
3037
3038
- if ( importClause = < ImportClause > getAncestor ( contextToken , SyntaxKind . ImportClause ) ) {
3038
+ if ( namedImportsOrExports = tryGetNamedImportsOrExportsForCompletion ( contextToken ) ) {
3039
3039
// cursor is in an import clause
3040
3040
// try to show exported member for imported module
3041
- return tryGetImportClauseCompletionSymbols ( importClause ) ;
3041
+ return tryGetImportOrExportClauseCompletionSymbols ( namedImportsOrExports ) ;
3042
3042
}
3043
3043
3044
3044
if ( jsxContainer = tryGetContainingJsxElement ( contextToken ) ) {
@@ -3048,7 +3048,7 @@ namespace ts {
3048
3048
attrsType = typeChecker . getJsxElementAttributesType ( < JsxOpeningLikeElement > jsxContainer ) ;
3049
3049
3050
3050
if ( attrsType ) {
3051
- symbols = filterJsxAttributes ( ( < JsxOpeningLikeElement > jsxContainer ) . attributes , typeChecker . getPropertiesOfType ( attrsType ) ) ;
3051
+ symbols = filterJsxAttributes ( typeChecker . getPropertiesOfType ( attrsType ) , ( < JsxOpeningLikeElement > jsxContainer ) . attributes ) ;
3052
3052
isMemberCompletion = true ;
3053
3053
isNewIdentifierLocation = false ;
3054
3054
return true ;
@@ -3117,24 +3117,12 @@ namespace ts {
3117
3117
function isCompletionListBlocker ( contextToken : Node ) : boolean {
3118
3118
let start = new Date ( ) . getTime ( ) ;
3119
3119
let result = isInStringOrRegularExpressionOrTemplateLiteral ( contextToken ) ||
3120
- isIdentifierDefinitionLocation ( contextToken ) ||
3120
+ isSolelyIdentifierDefinitionLocation ( contextToken ) ||
3121
3121
isDotOfNumericLiteral ( contextToken ) ;
3122
3122
log ( "getCompletionsAtPosition: isCompletionListBlocker: " + ( new Date ( ) . getTime ( ) - start ) ) ;
3123
3123
return result ;
3124
3124
}
3125
3125
3126
- function shouldShowCompletionsInImportsClause ( node : Node ) : boolean {
3127
- if ( node ) {
3128
- // import {|
3129
- // import {a,|
3130
- if ( node . kind === SyntaxKind . OpenBraceToken || node . kind === SyntaxKind . CommaToken ) {
3131
- return node . parent . kind === SyntaxKind . NamedImports ;
3132
- }
3133
- }
3134
-
3135
- return false ;
3136
- }
3137
-
3138
3126
function isNewIdentifierDefinitionLocation ( previousToken : Node ) : boolean {
3139
3127
if ( previousToken ) {
3140
3128
let containingNodeKind = previousToken . parent . kind ;
@@ -3266,38 +3254,42 @@ namespace ts {
3266
3254
}
3267
3255
3268
3256
/**
3269
- * Aggregates relevant symbols for completion in import clauses; for instance,
3257
+ * Aggregates relevant symbols for completion in import clauses and export clauses
3258
+ * whose declarations have a module specifier; for instance, symbols will be aggregated for
3259
+ *
3260
+ * import { | } from "moduleName";
3261
+ * export { a as foo, | } from "moduleName";
3270
3262
*
3271
- * import { $ } from "moduleName";
3263
+ * but not for
3264
+ *
3265
+ * export { | };
3272
3266
*
3273
3267
* Relevant symbols are stored in the captured 'symbols' variable.
3274
3268
*
3275
3269
* @returns true if 'symbols' was successfully populated; false otherwise.
3276
3270
*/
3277
- function tryGetImportClauseCompletionSymbols ( importClause : ImportClause ) : boolean {
3278
- // cursor is in import clause
3279
- // try to show exported member for imported module
3280
- if ( shouldShowCompletionsInImportsClause ( contextToken ) ) {
3281
- isMemberCompletion = true ;
3282
- isNewIdentifierLocation = false ;
3283
-
3284
- let importDeclaration = < ImportDeclaration > importClause . parent ;
3285
- Debug . assert ( importDeclaration !== undefined && importDeclaration . kind === SyntaxKind . ImportDeclaration ) ;
3271
+ function tryGetImportOrExportClauseCompletionSymbols ( namedImportsOrExports : NamedImportsOrExports ) : boolean {
3272
+ let declarationKind = namedImportsOrExports . kind === SyntaxKind . NamedImports ?
3273
+ SyntaxKind . ImportDeclaration :
3274
+ SyntaxKind . ExportDeclaration ;
3275
+ let importOrExportDeclaration = < ImportDeclaration | ExportDeclaration > getAncestor ( namedImportsOrExports , declarationKind ) ;
3276
+ let moduleSpecifier = importOrExportDeclaration . moduleSpecifier ;
3277
+
3278
+ if ( ! moduleSpecifier ) {
3279
+ return false ;
3280
+ }
3286
3281
3287
- let exports : Symbol [ ] ;
3288
- let moduleSpecifierSymbol = typeChecker . getSymbolAtLocation ( importDeclaration . moduleSpecifier ) ;
3289
- if ( moduleSpecifierSymbol ) {
3290
- exports = typeChecker . getExportsOfModule ( moduleSpecifierSymbol ) ;
3291
- }
3282
+ isMemberCompletion = true ;
3283
+ isNewIdentifierLocation = false ;
3292
3284
3293
- //let exports = typeInfoResolver.getExportsOfImportDeclaration(importDeclaration);
3294
- symbols = exports ? filterModuleExports ( exports , importDeclaration ) : emptyArray ;
3295
- }
3296
- else {
3297
- isMemberCompletion = false ;
3298
- isNewIdentifierLocation = true ;
3285
+ let exports : Symbol [ ] ;
3286
+ let moduleSpecifierSymbol = typeChecker . getSymbolAtLocation ( importOrExportDeclaration . moduleSpecifier ) ;
3287
+ if ( moduleSpecifierSymbol ) {
3288
+ exports = typeChecker . getExportsOfModule ( moduleSpecifierSymbol ) ;
3299
3289
}
3300
3290
3291
+ symbols = exports ? filterNamedImportOrExportCompletionItems ( exports , namedImportsOrExports . elements ) : emptyArray ;
3292
+
3301
3293
return true ;
3302
3294
}
3303
3295
@@ -3321,6 +3313,26 @@ namespace ts {
3321
3313
return undefined ;
3322
3314
}
3323
3315
3316
+ /**
3317
+ * Returns the containing list of named imports or exports of a context token,
3318
+ * on the condition that one exists and that the context implies completion should be given.
3319
+ */
3320
+ function tryGetNamedImportsOrExportsForCompletion ( contextToken : Node ) : NamedImportsOrExports {
3321
+ if ( contextToken ) {
3322
+ switch ( contextToken . kind ) {
3323
+ case SyntaxKind . OpenBraceToken : // import { |
3324
+ case SyntaxKind . CommaToken : // import { a as 0, |
3325
+ switch ( contextToken . parent . kind ) {
3326
+ case SyntaxKind . NamedImports :
3327
+ case SyntaxKind . NamedExports :
3328
+ return < NamedImportsOrExports > contextToken . parent ;
3329
+ }
3330
+ }
3331
+ }
3332
+
3333
+ return undefined ;
3334
+ }
3335
+
3324
3336
function tryGetContainingJsxElement ( contextToken : Node ) : JsxOpeningLikeElement {
3325
3337
if ( contextToken ) {
3326
3338
let parent = contextToken . parent ;
@@ -3368,7 +3380,10 @@ namespace ts {
3368
3380
return false ;
3369
3381
}
3370
3382
3371
- function isIdentifierDefinitionLocation ( contextToken : Node ) : boolean {
3383
+ /**
3384
+ * @returns true if we are certain that the currently edited location must define a new location; false otherwise.
3385
+ */
3386
+ function isSolelyIdentifierDefinitionLocation ( contextToken : Node ) : boolean {
3372
3387
let containingNodeKind = contextToken . parent . kind ;
3373
3388
switch ( contextToken . kind ) {
3374
3389
case SyntaxKind . CommaToken :
@@ -3425,6 +3440,11 @@ namespace ts {
3425
3440
case SyntaxKind . ProtectedKeyword :
3426
3441
return containingNodeKind === SyntaxKind . Parameter ;
3427
3442
3443
+ case SyntaxKind . AsKeyword :
3444
+ containingNodeKind === SyntaxKind . ImportSpecifier ||
3445
+ containingNodeKind === SyntaxKind . ExportSpecifier ||
3446
+ containingNodeKind === SyntaxKind . NamespaceImport ;
3447
+
3428
3448
case SyntaxKind . ClassKeyword :
3429
3449
case SyntaxKind . EnumKeyword :
3430
3450
case SyntaxKind . InterfaceKeyword :
@@ -3466,33 +3486,41 @@ namespace ts {
3466
3486
return false ;
3467
3487
}
3468
3488
3469
- function filterModuleExports ( exports : Symbol [ ] , importDeclaration : ImportDeclaration ) : Symbol [ ] {
3470
- let exisingImports : Map < boolean > = { } ;
3471
-
3472
- if ( ! importDeclaration . importClause ) {
3473
- return exports ;
3474
- }
3475
-
3476
- if ( importDeclaration . importClause . namedBindings &&
3477
- importDeclaration . importClause . namedBindings . kind === SyntaxKind . NamedImports ) {
3489
+ /**
3490
+ * Filters out completion suggestions for named imports or exports.
3491
+ *
3492
+ * @param exportsOfModule The list of symbols which a module exposes.
3493
+ * @param namedImportsOrExports The list of existing import/export specifiers in the import/export clause.
3494
+ *
3495
+ * @returns Symbols to be suggested at an import/export clause, barring those whose named imports/exports
3496
+ * do not occur at the current position and have not otherwise been typed.
3497
+ */
3498
+ function filterNamedImportOrExportCompletionItems ( exportsOfModule : Symbol [ ] , namedImportsOrExports : ImportOrExportSpecifier [ ] ) : Symbol [ ] {
3499
+ let exisingImportsOrExports : Map < boolean > = { } ;
3478
3500
3479
- forEach ( ( < NamedImports > importDeclaration . importClause . namedBindings ) . elements , el => {
3480
- // If this is the current item we are editing right now, do not filter it out
3481
- if ( el . getStart ( ) <= position && position <= el . getEnd ( ) ) {
3482
- return ;
3483
- }
3501
+ for ( let element of namedImportsOrExports ) {
3502
+ // If this is the current item we are editing right now, do not filter it out
3503
+ if ( element . getStart ( ) <= position && position <= element . getEnd ( ) ) {
3504
+ continue ;
3505
+ }
3484
3506
3485
- let name = el . propertyName || el . name ;
3486
- exisingImports [ name . text ] = true ;
3487
- } ) ;
3507
+ let name = element . propertyName || element . name ;
3508
+ exisingImportsOrExports [ name . text ] = true ;
3488
3509
}
3489
3510
3490
- if ( isEmpty ( exisingImports ) ) {
3491
- return exports ;
3511
+ if ( isEmpty ( exisingImportsOrExports ) ) {
3512
+ return exportsOfModule ;
3492
3513
}
3493
- return filter ( exports , e => ! lookUp ( exisingImports , e . name ) ) ;
3514
+
3515
+ return filter ( exportsOfModule , e => ! lookUp ( exisingImportsOrExports , e . name ) ) ;
3494
3516
}
3495
3517
3518
+ /**
3519
+ * Filters out completion suggestions for named imports or exports.
3520
+ *
3521
+ * @returns Symbols to be suggested in an object binding pattern or object literal expression, barring those whose declarations
3522
+ * do not occur at the current position and have not otherwise been typed.
3523
+ */
3496
3524
function filterObjectMembersList ( contextualMemberSymbols : Symbol [ ] , existingMembers : Declaration [ ] ) : Symbol [ ] {
3497
3525
if ( ! existingMembers || existingMembers . length === 0 ) {
3498
3526
return contextualMemberSymbols ;
@@ -3527,17 +3555,16 @@ namespace ts {
3527
3555
existingMemberNames [ existingName ] = true ;
3528
3556
}
3529
3557
3530
- let filteredMembers : Symbol [ ] = [ ] ;
3531
- forEach ( contextualMemberSymbols , s => {
3532
- if ( ! existingMemberNames [ s . name ] ) {
3533
- filteredMembers . push ( s ) ;
3534
- }
3535
- } ) ;
3536
-
3537
- return filteredMembers ;
3558
+ return filter ( contextualMemberSymbols , m => ! lookUp ( existingMemberNames , m . name ) ) ;
3538
3559
}
3539
3560
3540
- function filterJsxAttributes ( attributes : NodeArray < JsxAttribute | JsxSpreadAttribute > , symbols : Symbol [ ] ) : Symbol [ ] {
3561
+ /**
3562
+ * Filters out completion suggestions from 'symbols' according to existing JSX attributes.
3563
+ *
3564
+ * @returns Symbols to be suggested in a JSX element, barring those whose attributes
3565
+ * do not occur at the current position and have not otherwise been typed.
3566
+ */
3567
+ function filterJsxAttributes ( symbols : Symbol [ ] , attributes : NodeArray < JsxAttribute | JsxSpreadAttribute > ) : Symbol [ ] {
3541
3568
let seenNames : Map < boolean > = { } ;
3542
3569
for ( let attr of attributes ) {
3543
3570
// If this is the current item we are editing right now, do not filter it out
@@ -3549,13 +3576,8 @@ namespace ts {
3549
3576
seenNames [ ( < JsxAttribute > attr ) . name . text ] = true ;
3550
3577
}
3551
3578
}
3552
- let result : Symbol [ ] = [ ] ;
3553
- for ( let sym of symbols ) {
3554
- if ( ! seenNames [ sym . name ] ) {
3555
- result . push ( sym ) ;
3556
- }
3557
- }
3558
- return result ;
3579
+
3580
+ return filter ( symbols , a => ! lookUp ( seenNames , a . name ) ) ;
3559
3581
}
3560
3582
}
3561
3583
0 commit comments