-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Unmangle scoped package names in import completions #21131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
fa758cc
db09a59
e48312d
71c92bf
5d8598f
8275bed
ff102da
211be0a
9a4fe8e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -312,9 +312,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) { | ||
|
|
@@ -326,32 +328,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); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method is optional -- our test runner will always provide it though, so this assertion won't fail in any tests.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure exactly what you're suggestion (remove the assertion?) but I included this assertion because the code was extracted from under an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whoops, didn't notice that there's still an |
||
| 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[] { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 }, | ||
| ]); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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] }, | ||
| ]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a test that fails without this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, I meant to.