diff --git a/src/services/completions.ts b/src/services/completions.ts index f0ad156956d82..89b15e9065a2f 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -652,7 +652,7 @@ namespace ts.Completions { const contextToken = findPrecedingToken(position, sourceFile); if (isInString(sourceFile, position, contextToken)) { - return StringCompletions.getStringLiteralCompletionDetails(name, sourceFile, position, contextToken, typeChecker, compilerOptions, host, cancellationToken); + return StringCompletions.getStringLiteralCompletionDetails(name, sourceFile, position, contextToken, typeChecker, compilerOptions, host, cancellationToken, preferences); } // Compute all the completion symbols again. diff --git a/src/services/stringCompletions.ts b/src/services/stringCompletions.ts index de823ad951d0e..12a3d724e7b82 100644 --- a/src/services/stringCompletions.ts +++ b/src/services/stringCompletions.ts @@ -7,7 +7,7 @@ namespace ts.Completions.StringCompletions { } if (isInString(sourceFile, position, contextToken)) { if (!contextToken || !isStringLiteralLike(contextToken)) return undefined; - const entries = getStringLiteralCompletionEntries(sourceFile, contextToken, position, checker, options, host); + const entries = getStringLiteralCompletionEntries(sourceFile, contextToken, position, checker, options, host, preferences); return convertStringLiteralCompletions(entries, contextToken, sourceFile, checker, log, preferences); } } @@ -52,9 +52,9 @@ namespace ts.Completions.StringCompletions { } } - export function getStringLiteralCompletionDetails(name: string, sourceFile: SourceFile, position: number, contextToken: Node | undefined, checker: TypeChecker, options: CompilerOptions, host: LanguageServiceHost, cancellationToken: CancellationToken) { + export function getStringLiteralCompletionDetails(name: string, sourceFile: SourceFile, position: number, contextToken: Node | undefined, checker: TypeChecker, options: CompilerOptions, host: LanguageServiceHost, cancellationToken: CancellationToken, preferences: UserPreferences) { if (!contextToken || !isStringLiteralLike(contextToken)) return undefined; - const completions = getStringLiteralCompletionEntries(sourceFile, contextToken, position, checker, options, host); + const completions = getStringLiteralCompletionEntries(sourceFile, contextToken, position, checker, options, host, preferences); return completions && stringLiteralCompletionDetails(name, contextToken, completions, sourceFile, checker, cancellationToken); } @@ -109,7 +109,7 @@ namespace ts.Completions.StringCompletions { readonly isNewIdentifier: boolean; } type StringLiteralCompletion = { readonly kind: StringLiteralCompletionKind.Paths, readonly paths: readonly PathCompletion[] } | StringLiteralCompletionsFromProperties | StringLiteralCompletionsFromTypes; - function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringLiteralLike, position: number, typeChecker: TypeChecker, compilerOptions: CompilerOptions, host: LanguageServiceHost): StringLiteralCompletion | undefined { + function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringLiteralLike, position: number, typeChecker: TypeChecker, compilerOptions: CompilerOptions, host: LanguageServiceHost, preferences: UserPreferences): StringLiteralCompletion | undefined { const parent = walkUpParentheses(node.parent); switch (parent.kind) { case SyntaxKind.LiteralType: { @@ -136,7 +136,7 @@ namespace ts.Completions.StringCompletions { } return stringLiteralCompletionsFromProperties(typeChecker.getTypeFromTypeNode(objectType)); case SyntaxKind.ImportType: - return { kind: StringLiteralCompletionKind.Paths, paths: getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker) }; + return { kind: StringLiteralCompletionKind.Paths, paths: getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker, preferences) }; case SyntaxKind.UnionType: { if (!isTypeReferenceNode(grandParent.parent)) { return undefined; @@ -201,7 +201,7 @@ namespace ts.Completions.StringCompletions { // import x = require("/*completion position*/"); // var y = require("/*completion position*/"); // export * from "/*completion position*/"; - return { kind: StringLiteralCompletionKind.Paths, paths: getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker) }; + return { kind: StringLiteralCompletionKind.Paths, paths: getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker, preferences) }; default: return fromContextualType(); @@ -303,18 +303,18 @@ namespace ts.Completions.StringCompletions { Math.max(name.indexOf(directorySeparator), name.indexOf(altDirectorySeparator)) !== -1 ? { name, kind, extension, span: wholeSpan } : { name, kind, extension, span }); } - function getStringLiteralCompletionsFromModuleNames(sourceFile: SourceFile, node: LiteralExpression, compilerOptions: CompilerOptions, host: LanguageServiceHost, typeChecker: TypeChecker): readonly PathCompletion[] { - return addReplacementSpans(node.text, node.getStart(sourceFile) + 1, getStringLiteralCompletionsFromModuleNamesWorker(sourceFile, node, compilerOptions, host, typeChecker)); + function getStringLiteralCompletionsFromModuleNames(sourceFile: SourceFile, node: LiteralExpression, compilerOptions: CompilerOptions, host: LanguageServiceHost, typeChecker: TypeChecker, preferences: UserPreferences): readonly PathCompletion[] { + return addReplacementSpans(node.text, node.getStart(sourceFile) + 1, getStringLiteralCompletionsFromModuleNamesWorker(sourceFile, node, compilerOptions, host, typeChecker, preferences)); } - function getStringLiteralCompletionsFromModuleNamesWorker(sourceFile: SourceFile, node: LiteralExpression, compilerOptions: CompilerOptions, host: LanguageServiceHost, typeChecker: TypeChecker): readonly NameAndKind[] { + function getStringLiteralCompletionsFromModuleNamesWorker(sourceFile: SourceFile, node: LiteralExpression, compilerOptions: CompilerOptions, host: LanguageServiceHost, typeChecker: TypeChecker, preferences: UserPreferences): readonly NameAndKind[] { const literalValue = normalizeSlashes(node.text); const scriptPath = sourceFile.path; const scriptDirectory = getDirectoryPath(scriptPath); return isPathRelativeToScript(literalValue) || !compilerOptions.baseUrl && (isRootedDiskPath(literalValue) || isUrl(literalValue)) - ? getCompletionEntriesForRelativeModules(literalValue, scriptDirectory, compilerOptions, host, scriptPath) + ? getCompletionEntriesForRelativeModules(literalValue, scriptDirectory, compilerOptions, host, scriptPath, preferences) : getCompletionEntriesForNonRelativeModules(literalValue, scriptDirectory, compilerOptions, host, typeChecker); } @@ -325,8 +325,8 @@ namespace ts.Completions.StringCompletions { function getExtensionOptions(compilerOptions: CompilerOptions, includeExtensions = false): ExtensionOptions { return { extensions: getSupportedExtensionsForModuleResolution(compilerOptions), includeExtensions }; } - function getCompletionEntriesForRelativeModules(literalValue: string, scriptDirectory: string, compilerOptions: CompilerOptions, host: LanguageServiceHost, scriptPath: Path) { - const extensionOptions = getExtensionOptions(compilerOptions); + function getCompletionEntriesForRelativeModules(literalValue: string, scriptDirectory: string, compilerOptions: CompilerOptions, host: LanguageServiceHost, scriptPath: Path, preferences: UserPreferences) { + const extensionOptions = getExtensionOptions(compilerOptions, preferences.importModuleSpecifierEnding === "js"); if (compilerOptions.rootDirs) { return getCompletionEntriesForDirectoryFragmentWithRootDirs( compilerOptions.rootDirs, literalValue, scriptDirectory, extensionOptions, compilerOptions, host, scriptPath); diff --git a/tests/cases/fourslash/completionImportModuleSpecifierEnding.ts b/tests/cases/fourslash/completionImportModuleSpecifierEnding.ts new file mode 100644 index 0000000000000..7771a9ac781d3 --- /dev/null +++ b/tests/cases/fourslash/completionImportModuleSpecifierEnding.ts @@ -0,0 +1,12 @@ +/// +//@allowJs: true +//@Filename:test.js +////export function f(){ +//// return 1 +////} + +//@Filename:module.js +////import { f } from ".//**/" + + +verify.completions({ marker: "", includes:{name:"test.js"}, preferences: {importModuleSpecifierEnding: "js" }, isNewIdentifierLocation: true}) \ No newline at end of file