mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-07 23:08:20 -06:00
Merge pull request #21131 from amcasey/GH15533
Unmangle scoped package names in import completions
This commit is contained in:
commit
e3da8fb526
@ -1097,13 +1097,18 @@ namespace ts {
|
||||
export function getPackageNameFromAtTypesDirectory(mangledName: string): string {
|
||||
const withoutAtTypePrefix = removePrefix(mangledName, "@types/");
|
||||
if (withoutAtTypePrefix !== mangledName) {
|
||||
return stringContains(withoutAtTypePrefix, mangledScopedPackageSeparator) ?
|
||||
"@" + withoutAtTypePrefix.replace(mangledScopedPackageSeparator, ts.directorySeparator) :
|
||||
withoutAtTypePrefix;
|
||||
return getUnmangledNameForScopedPackage(withoutAtTypePrefix);
|
||||
}
|
||||
return mangledName;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function getUnmangledNameForScopedPackage(typesPackageName: string): string {
|
||||
return stringContains(typesPackageName, mangledScopedPackageSeparator) ?
|
||||
"@" + typesPackageName.replace(mangledScopedPackageSeparator, ts.directorySeparator) :
|
||||
typesPackageName;
|
||||
}
|
||||
|
||||
function tryFindNonRelativeModuleNameInCache(cache: PerModuleNameCache | undefined, moduleName: string, containingDirectory: string, traceEnabled: boolean, host: ModuleResolutionHost): SearchResult<Resolved> {
|
||||
const result = cache && cache.get(containingDirectory);
|
||||
if (result) {
|
||||
|
||||
@ -314,9 +314,11 @@ namespace ts.Completions.PathCompletions {
|
||||
|
||||
function getCompletionEntriesFromTypings(host: LanguageServiceHost, options: CompilerOptions, scriptPath: string, span: TextSpan, result: CompletionEntry[] = []): CompletionEntry[] {
|
||||
// Check for typings specified in compiler options
|
||||
const seen = createMap<true>();
|
||||
if (options.types) {
|
||||
for (const moduleName of options.types) {
|
||||
result.push(createCompletionEntryForModule(moduleName, ScriptElementKind.externalModuleName, span));
|
||||
for (const typesName of options.types) {
|
||||
const moduleName = getUnmangledNameForScopedPackage(typesName);
|
||||
pushResult(moduleName);
|
||||
}
|
||||
}
|
||||
else if (host.getDirectories) {
|
||||
@ -328,32 +330,40 @@ namespace ts.Completions.PathCompletions {
|
||||
|
||||
if (typeRoots) {
|
||||
for (const root of typeRoots) {
|
||||
getCompletionEntriesFromDirectories(host, root, span, result);
|
||||
getCompletionEntriesFromDirectories(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (host.getDirectories) {
|
||||
// Also get all @types typings installed in visible node_modules directories
|
||||
for (const packageJson of findPackageJsons(scriptPath, host)) {
|
||||
const typesDir = combinePaths(getDirectoryPath(packageJson), "node_modules/@types");
|
||||
getCompletionEntriesFromDirectories(host, typesDir, span, result);
|
||||
getCompletionEntriesFromDirectories(typesDir);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function getCompletionEntriesFromDirectories(host: LanguageServiceHost, directory: string, span: TextSpan, result: Push<CompletionEntry>) {
|
||||
if (host.getDirectories && tryDirectoryExists(host, directory)) {
|
||||
const directories = tryGetDirectories(host, directory);
|
||||
if (directories) {
|
||||
for (let typeDirectory of directories) {
|
||||
typeDirectory = normalizePath(typeDirectory);
|
||||
result.push(createCompletionEntryForModule(getBaseFileName(typeDirectory), ScriptElementKind.externalModuleName, span));
|
||||
function getCompletionEntriesFromDirectories(directory: string) {
|
||||
Debug.assert(!!host.getDirectories);
|
||||
if (tryDirectoryExists(host, directory)) {
|
||||
const directories = tryGetDirectories(host, directory);
|
||||
if (directories) {
|
||||
for (let typeDirectory of directories) {
|
||||
typeDirectory = normalizePath(typeDirectory);
|
||||
const directoryName = getBaseFileName(typeDirectory);
|
||||
const moduleName = getUnmangledNameForScopedPackage(directoryName);
|
||||
pushResult(moduleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function pushResult(moduleName: string) {
|
||||
if (!seen.has(moduleName)) {
|
||||
result.push(createCompletionEntryForModule(moduleName, ScriptElementKind.externalModuleName, span));
|
||||
seen.set(moduleName, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findPackageJsons(directory: string, host: LanguageServiceHost): string[] {
|
||||
|
||||
20
tests/cases/fourslash/completionListInImportClause05.ts
Normal file
20
tests/cases/fourslash/completionListInImportClause05.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: app.ts
|
||||
////import * as A from "[|/*1*/|]";
|
||||
|
||||
// @Filename: /node_modules/@types/a__b/index.d.ts
|
||||
////declare module "@e/f" { function fun(): string; }
|
||||
|
||||
// @Filename: /node_modules/@types/c__d/index.d.ts
|
||||
////export declare let x: number;
|
||||
|
||||
// NOTE: The node_modules folder is in "/", rather than ".", because it requires
|
||||
// less scaffolding to mock. In particular, "/" is where we look for type roots.
|
||||
|
||||
const [replacementSpan] = test.ranges();
|
||||
verify.completionsAt("1", [
|
||||
{ name: "@a/b", replacementSpan },
|
||||
{ name: "@c/d", replacementSpan },
|
||||
{ name: "@e/f", replacementSpan },
|
||||
]);
|
||||
17
tests/cases/fourslash/completionListInImportClause06.ts
Normal file
17
tests/cases/fourslash/completionListInImportClause06.ts
Normal file
@ -0,0 +1,17 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @typeRoots: T1,T2
|
||||
|
||||
// @Filename: app.ts
|
||||
////import * as A from "[|/*1*/|]";
|
||||
|
||||
// @Filename: T1/a__b/index.d.ts
|
||||
////export declare let x: number;
|
||||
|
||||
// @Filename: T2/a__b/index.d.ts
|
||||
////export declare let x: number;
|
||||
|
||||
// Confirm that entries are de-dup'd.
|
||||
verify.completionsAt("1", [
|
||||
{ name: "@a/b", replacementSpan: test.ranges()[0] },
|
||||
]);
|
||||
Loading…
x
Reference in New Issue
Block a user