Skip to content

Commit a1ffa94

Browse files
author
Andy
authored
Fix ScriptElementKind for path mapping completions (microsoft#21695)
1 parent c48afe7 commit a1ffa94

File tree

2 files changed

+47
-15
lines changed

2 files changed

+47
-15
lines changed

src/services/pathCompletions.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
/* @internal */
22
namespace ts.Completions.PathCompletions {
3-
export interface PathCompletion {
3+
export interface NameAndKind {
44
readonly name: string;
55
readonly kind: ScriptElementKind.scriptElement | ScriptElementKind.directory | ScriptElementKind.externalModuleName;
6+
}
7+
export interface PathCompletion extends NameAndKind {
68
readonly span: TextSpan;
79
}
810
function createPathCompletion(name: string, kind: PathCompletion["kind"], span: TextSpan): PathCompletion {
@@ -158,10 +160,10 @@ namespace ts.Completions.PathCompletions {
158160
for (const path in paths) {
159161
const patterns = paths[path];
160162
if (paths.hasOwnProperty(path) && patterns) {
161-
for (const pathCompletion of getCompletionsForPathMapping(path, patterns, fragment, baseUrl, fileExtensions, host)) {
163+
for (const { name, kind } of getCompletionsForPathMapping(path, patterns, fragment, baseUrl, fileExtensions, host)) {
162164
// Path mappings may provide a duplicate way to get to something we've already added, so don't add again.
163-
if (!result.some(entry => entry.name === pathCompletion)) {
164-
result.push(createPathCompletion(pathCompletion, ScriptElementKind.externalModuleName, span));
165+
if (!result.some(entry => entry.name === name)) {
166+
result.push(createPathCompletion(name, kind, span));
165167
}
166168
}
167169
}
@@ -188,22 +190,22 @@ namespace ts.Completions.PathCompletions {
188190

189191
function getCompletionsForPathMapping(
190192
path: string, patterns: ReadonlyArray<string>, fragment: string, baseUrl: string, fileExtensions: ReadonlyArray<string>, host: LanguageServiceHost,
191-
): ReadonlyArray<string> {
193+
): ReadonlyArray<NameAndKind> {
192194
if (!endsWith(path, "*")) {
193195
// For a path mapping "foo": ["/x/y/z.ts"], add "foo" itself as a completion.
194-
return !stringContains(path, "*") && startsWith(path, fragment) ? [path] : emptyArray;
196+
return !stringContains(path, "*") && startsWith(path, fragment) ? [{ name: path, kind: ScriptElementKind.directory }] : emptyArray;
195197
}
196198

197199
const pathPrefix = path.slice(0, path.length - 1);
198200
if (!startsWith(fragment, pathPrefix)) {
199-
return [pathPrefix];
201+
return [{ name: pathPrefix, kind: ScriptElementKind.directory }];
200202
}
201203

202204
const remainingFragment = fragment.slice(pathPrefix.length);
203205
return flatMap(patterns, pattern => getModulesForPathsPattern(remainingFragment, baseUrl, pattern, fileExtensions, host));
204206
}
205207

206-
function getModulesForPathsPattern(fragment: string, baseUrl: string, pattern: string, fileExtensions: ReadonlyArray<string>, host: LanguageServiceHost): string[] | undefined {
208+
function getModulesForPathsPattern(fragment: string, baseUrl: string, pattern: string, fileExtensions: ReadonlyArray<string>, host: LanguageServiceHost): ReadonlyArray<NameAndKind> | undefined {
207209
if (!host.readDirectory) {
208210
return undefined;
209211
}
@@ -234,14 +236,14 @@ namespace ts.Completions.PathCompletions {
234236
// doesn't support. For now, this is safer but slower
235237
const includeGlob = normalizedSuffix ? "**/*" : "./*";
236238

237-
const matches = tryReadDirectory(host, baseDirectory, fileExtensions, /*exclude*/ undefined, [includeGlob]);
238-
const directories = tryGetDirectories(host, baseDirectory).map(d => combinePaths(baseDirectory, d));
239+
const matches = tryReadDirectory(host, baseDirectory, fileExtensions, /*exclude*/ undefined, [includeGlob]).map<NameAndKind>(name => ({ name, kind: ScriptElementKind.scriptElement }));
240+
const directories = tryGetDirectories(host, baseDirectory).map(d => combinePaths(baseDirectory, d)).map<NameAndKind>(name => ({ name, kind: ScriptElementKind.directory }));
239241

240242
// Trim away prefix and suffix
241-
return mapDefined(concatenate(matches, directories), match => {
242-
const normalizedMatch = normalizePath(match);
243+
return mapDefined<NameAndKind, NameAndKind>(concatenate(matches, directories), ({ name, kind }) => {
244+
const normalizedMatch = normalizePath(name);
243245
const inner = withoutStartAndEnd(normalizedMatch, completePrefix, normalizedSuffix);
244-
return inner !== undefined ? removeLeadingDirectorySeparator(removeFileExtension(inner)) : undefined;
246+
return inner !== undefined ? { name: removeLeadingDirectorySeparator(removeFileExtension(inner)), kind } : undefined;
245247
});
246248
}
247249

@@ -488,8 +490,8 @@ namespace ts.Completions.PathCompletions {
488490
return tryIOAndConsumeErrors(host, host.getDirectories, directoryName) || [];
489491
}
490492

491-
function tryReadDirectory(host: LanguageServiceHost, path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>): string[] | undefined | undefined {
492-
return tryIOAndConsumeErrors(host, host.readDirectory, path, extensions, exclude, include);
493+
function tryReadDirectory(host: LanguageServiceHost, path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>): ReadonlyArray<string> {
494+
return tryIOAndConsumeErrors(host, host.readDirectory, path, extensions, exclude, include) || emptyArray;
493495
}
494496

495497
function tryReadFile(host: LanguageServiceHost, path: string): string | undefined {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @Filename: /src/b.ts
4+
////not read
5+
6+
// @Filename: /src/dir/x.ts
7+
////not read
8+
9+
// @Filename: /src/a.ts
10+
////import {} from "./[|/*0*/|]";
11+
////import {} from "./[|/*1*/|]";
12+
13+
// @Filename: /tsconfig.json
14+
////{
15+
//// "compilerOptions": {
16+
//// "baseUrl": ".",
17+
//// "paths": {
18+
//// "foo/*": ["src/*"]
19+
//// }
20+
//// }
21+
////}
22+
23+
goTo.marker("0");
24+
verify.completionListContains("dir", undefined, undefined, "directory");
25+
verify.completionListContains("b", undefined, undefined, "script");
26+
27+
goTo.marker("1");
28+
verify.completionListContains("dir", undefined, undefined, "directory");
29+
verify.completionListContains("b", undefined, undefined, "script");
30+

0 commit comments

Comments
 (0)