@@ -35,11 +35,14 @@ namespace ts.Completions {
35
35
return entries && pathCompletionsInfo ( entries ) ;
36
36
}
37
37
38
- if ( isInString ( sourceFile , position ) ) {
39
- return getStringLiteralCompletionEntries ( sourceFile , position , typeChecker , compilerOptions , host , log ) ;
38
+ const contextToken = findPrecedingToken ( position , sourceFile ) ;
39
+
40
+ if ( isInString ( sourceFile , position , contextToken ) ) {
41
+ return ! contextToken || ! isStringLiteral ( contextToken ) && ! isNoSubstitutionTemplateLiteral ( contextToken )
42
+ ? undefined
43
+ : getStringLiteralCompletionEntries ( sourceFile , contextToken , position , typeChecker , compilerOptions , host , log ) ;
40
44
}
41
45
42
- const contextToken = findPrecedingToken ( position , sourceFile ) ;
43
46
if ( contextToken && isBreakOrContinueStatement ( contextToken . parent )
44
47
&& ( contextToken . kind === SyntaxKind . BreakKeyword || contextToken . kind === SyntaxKind . ContinueKeyword || contextToken . kind === SyntaxKind . Identifier ) ) {
45
48
return getLabelCompletionAtPosition ( contextToken . parent ) ;
@@ -261,70 +264,87 @@ namespace ts.Completions {
261
264
}
262
265
}
263
266
264
- function getStringLiteralCompletionEntries ( sourceFile : SourceFile , position : number , typeChecker : TypeChecker , compilerOptions : CompilerOptions , host : LanguageServiceHost , log : Log ) : CompletionInfo | undefined {
265
- const node = findPrecedingToken ( position , sourceFile ) ;
266
- if ( ! node || ! isStringLiteral ( node ) && ! isNoSubstitutionTemplateLiteral ( node ) ) {
267
- return undefined ;
268
- }
267
+ function getStringLiteralCompletionEntries ( sourceFile : SourceFile , node : StringLiteralLike , position : number , typeChecker : TypeChecker , compilerOptions : CompilerOptions , host : LanguageServiceHost , log : Log ) : CompletionInfo | undefined {
268
+ switch ( node . parent . kind ) {
269
+ case SyntaxKind . LiteralType :
270
+ switch ( node . parent . parent . kind ) {
271
+ case SyntaxKind . TypeReference :
272
+ // TODO: GH#21168
273
+ return undefined ;
274
+ case SyntaxKind . IndexedAccessType :
275
+ // Get all apparent property names
276
+ // i.e. interface Foo {
277
+ // foo: string;
278
+ // bar: string;
279
+ // }
280
+ // let x: Foo["/*completion position*/"]
281
+ const type = typeChecker . getTypeFromTypeNode ( ( node . parent . parent as IndexedAccessTypeNode ) . objectType ) ;
282
+ return getStringLiteralCompletionEntriesFromElementAccessOrIndexedAccess ( node , sourceFile , type , typeChecker , compilerOptions . target , log ) ;
283
+ default :
284
+ return undefined ;
285
+ }
269
286
270
- if ( node . parent . kind === SyntaxKind . PropertyAssignment &&
271
- node . parent . parent . kind === SyntaxKind . ObjectLiteralExpression &&
272
- ( < PropertyAssignment > node . parent ) . name === node ) {
273
- // Get quoted name of properties of the object literal expression
274
- // i.e. interface ConfigFiles {
275
- // 'jspm:dev': string
276
- // }
277
- // let files: ConfigFiles = {
278
- // '/*completion position*/'
279
- // }
280
- //
281
- // function foo(c: ConfigFiles) {}
282
- // foo({
283
- // '/*completion position*/'
284
- // });
285
- return getStringLiteralCompletionEntriesFromPropertyAssignment ( < ObjectLiteralElement > node . parent , sourceFile , typeChecker , compilerOptions . target , log ) ;
286
- }
287
- else if ( isElementAccessExpression ( node . parent ) && node . parent . argumentExpression === node ) {
288
- // Get all names of properties on the expression
289
- // i.e. interface A {
290
- // 'prop1': string
291
- // }
292
- // let a: A;
293
- // a['/*completion position*/']
294
- const type = typeChecker . getTypeAtLocation ( node . parent . expression ) ;
295
- return getStringLiteralCompletionEntriesFromElementAccessOrIndexedAccess ( node , sourceFile , type , typeChecker , compilerOptions . target , log ) ;
296
- }
297
- else if ( node . parent . kind === SyntaxKind . ImportDeclaration || node . parent . kind === SyntaxKind . ExportDeclaration
298
- || isRequireCall ( node . parent , /*checkArgumentIsStringLiteral*/ false ) || isImportCall ( node . parent )
299
- || isExpressionOfExternalModuleImportEqualsDeclaration ( node ) ) {
300
- // Get all known external module names or complete a path to a module
301
- // i.e. import * as ns from "/*completion position*/";
302
- // var y = import("/*completion position*/");
303
- // import x = require("/*completion position*/");
304
- // var y = require("/*completion position*/");
305
- // export * from "/*completion position*/";
306
- const entries = PathCompletions . getStringLiteralCompletionsFromModuleNames ( sourceFile , node , compilerOptions , host , typeChecker ) ;
307
- return pathCompletionsInfo ( entries ) ;
308
- }
309
- else if ( isIndexedAccessTypeNode ( node . parent . parent ) ) {
310
- // Get all apparent property names
311
- // i.e. interface Foo {
312
- // foo: string;
313
- // bar: string;
314
- // }
315
- // let x: Foo["/*completion position*/"]
316
- const type = typeChecker . getTypeFromTypeNode ( node . parent . parent . objectType ) ;
317
- return getStringLiteralCompletionEntriesFromElementAccessOrIndexedAccess ( node , sourceFile , type , typeChecker , compilerOptions . target , log ) ;
318
- }
319
- else {
320
- const argumentInfo = SignatureHelp . getImmediatelyContainingArgumentInfo ( node , position , sourceFile ) ;
321
- if ( argumentInfo ) {
322
- // Get string literal completions from specialized signatures of the target
323
- // i.e. declare function f(a: 'A');
324
- // f("/*completion position*/")
325
- return getStringLiteralCompletionEntriesFromCallExpression ( argumentInfo , typeChecker ) ;
287
+ case SyntaxKind . PropertyAssignment :
288
+ if ( node . parent . parent . kind === SyntaxKind . ObjectLiteralExpression &&
289
+ ( < PropertyAssignment > node . parent ) . name === node ) {
290
+ // Get quoted name of properties of the object literal expression
291
+ // i.e. interface ConfigFiles {
292
+ // 'jspm:dev': string
293
+ // }
294
+ // let files: ConfigFiles = {
295
+ // '/*completion position*/'
296
+ // }
297
+ //
298
+ // function foo(c: ConfigFiles) {}
299
+ // foo({
300
+ // '/*completion position*/'
301
+ // });
302
+ return getStringLiteralCompletionEntriesFromPropertyAssignment ( < PropertyAssignment > node . parent , sourceFile , typeChecker , compilerOptions . target , log ) ;
303
+ }
304
+ return fromContextualType ( ) ;
305
+
306
+ case SyntaxKind . ElementAccessExpression : {
307
+ const { expression, argumentExpression } = node . parent as ElementAccessExpression ;
308
+ if ( node === argumentExpression ) {
309
+ // Get all names of properties on the expression
310
+ // i.e. interface A {
311
+ // 'prop1': string
312
+ // }
313
+ // let a: A;
314
+ // a['/*completion position*/']
315
+ const type = typeChecker . getTypeAtLocation ( expression ) ;
316
+ return getStringLiteralCompletionEntriesFromElementAccessOrIndexedAccess ( node , sourceFile , type , typeChecker , compilerOptions . target , log ) ;
317
+ }
318
+ break ;
326
319
}
327
320
321
+ case SyntaxKind . CallExpression :
322
+ case SyntaxKind . NewExpression :
323
+ if ( ! isRequireCall ( node . parent , /*checkArgumentIsStringLiteral*/ false ) && ! isImportCall ( node . parent ) ) {
324
+ const argumentInfo = SignatureHelp . getImmediatelyContainingArgumentInfo ( node , position , sourceFile ) ;
325
+ // Get string literal completions from specialized signatures of the target
326
+ // i.e. declare function f(a: 'A');
327
+ // f("/*completion position*/")
328
+ return argumentInfo ? getStringLiteralCompletionEntriesFromCallExpression ( argumentInfo , typeChecker ) : fromContextualType ( ) ;
329
+ }
330
+ // falls through
331
+
332
+ case SyntaxKind . ImportDeclaration :
333
+ case SyntaxKind . ExportDeclaration :
334
+ case SyntaxKind . ExternalModuleReference :
335
+ // Get all known external module names or complete a path to a module
336
+ // i.e. import * as ns from "/*completion position*/";
337
+ // var y = import("/*completion position*/");
338
+ // import x = require("/*completion position*/");
339
+ // var y = require("/*completion position*/");
340
+ // export * from "/*completion position*/";
341
+ return pathCompletionsInfo ( PathCompletions . getStringLiteralCompletionsFromModuleNames ( sourceFile , node as StringLiteral , compilerOptions , host , typeChecker ) ) ;
342
+
343
+ default :
344
+ return fromContextualType ( ) ;
345
+ }
346
+
347
+ function fromContextualType ( ) : CompletionInfo {
328
348
// Get completion for string literal from string literal type
329
349
// i.e. var x: "hi" | "hello" = "/*completion position*/"
330
350
return getStringLiteralCompletionEntriesFromType ( getContextualTypeFromParent ( node , typeChecker ) , typeChecker ) ;
0 commit comments