Skip to content

Unmangle scoped package names in import completions#21131

Merged
amcasey merged 9 commits into
microsoft:masterfrom
amcasey:GH15533
Jan 11, 2018
Merged

Unmangle scoped package names in import completions#21131
amcasey merged 9 commits into
microsoft:masterfrom
amcasey:GH15533

Conversation

@amcasey
Copy link
Copy Markdown
Member

@amcasey amcasey commented Jan 10, 2018

"@" is only allowed at the start of a package name, so the types for package @a/b are put in @types/a__b. We want completion to offer @a/b, rather than a__b.

Note that, in at least some cases, it is impossible to determine whether @types/a__b came from @a/b or a__b. We don't try to distinguish - we always offer @a/b. (Conceivably, we could switch to a__b if it resolves and @a/b does not but, at present, there are no typings for packages with "__" in the name.)

Fixes #15533

@amcasey amcasey requested a review from a user January 10, 2018 22:02
Comment thread src/services/pathCompletions.ts Outdated
for (const moduleName of options.types) {
result.push(createCompletionEntryForModule(moduleName, ScriptElementKind.externalModuleName, span));
for (const typesName of options.types) {
const moduleName = getPackageNameFromAtTypesDirectoryWithoutPrefix(typesName);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: don't really need the local

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, but I found it helpful for debugging.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If debugging in chrome you can actually see the return value before exiting a function even if it's not named. That's in "Scope > Local > Return value" in the right-hand menu.

typeDirectory = normalizePath(typeDirectory);
result.push(createCompletionEntryForModule(getBaseFileName(typeDirectory), ScriptElementKind.externalModuleName, span));
function getCompletionEntriesFromDirectories(directory: string) {
Debug.assert(!!host.getDirectories);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The 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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The 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 if (host.getDirectories) check. Possibly you're suggesting that that check isn't required either?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, didn't notice that there's still an if, thought it was an assertion now.
Although it looks like tryIOAndConsumeErrors already handles the method being undefined, so the if may be unnecessary anyway.

// @Filename: /node_modules/@types/c__d/index.d.ts
////export declare let x: number;

// NOTE: When performing completion, the "current directory" appears to be "/",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this may be a correct behavior -- host.getCurrentDirectory() returns process.cwd();, not necessarily the root of your project.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've refined the comment.

Comment thread src/compiler/moduleNameResolver.ts Outdated
}

/* @internal */
export function getPackageNameFromAtTypesDirectoryWithoutPrefix(withoutAtTypePrefix: string): string {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would call this unmangleTypesPackageName, and the parameter typesPackageName.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went with getUnmangledNameForScopedPackage for consistency with getMangledNameForScopedPackage.


function getCompletionEntriesFromTypings(host: LanguageServiceHost, options: CompilerOptions, scriptPath: string, span: TextSpan, result: CompletionEntry[] = []): CompletionEntry[] {
// Check for typings specified in compiler options
const seen = createMap<true>();
Copy link
Copy Markdown

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?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, I meant to.

@amcasey amcasey merged commit e3da8fb into microsoft:master Jan 11, 2018
@amcasey amcasey deleted the GH15533 branch January 11, 2018 19:03
@microsoft microsoft locked and limited conversation to collaborators Jul 3, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bad Completion on import of scoped package defined with @types

1 participant