diff --git a/src/services/completions.ts b/src/services/completions.ts index f0ad156956d82..e7b1a8e86bdd4 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -855,6 +855,7 @@ namespace ts.Completions { host: LanguageServiceHost ): CompletionData | Request | undefined { const typeChecker = program.getTypeChecker(); + const compilerOptions = program.getCompilerOptions(); let start = timestamp(); let currentToken = getTokenAtPosition(sourceFile, position); // TODO: GH#15853 @@ -1519,7 +1520,22 @@ namespace ts.Completions { return false; } - symbol = skipAlias(symbol, typeChecker); + // External modules can have global export declarations that will be + // available as global keywords in all scopes. But if the external module + // already has an explicit export and user only wants to user explicit + // module imports then the global keywords will be filtered out so auto + // import suggestions will win in the completion + const symbolOrigin = skipAlias(symbol, typeChecker); + // We only want to filter out the global keywords + // Auto Imports are not available for scripts so this conditional is always false + if (!!sourceFile.externalModuleIndicator + && !compilerOptions.allowUmdGlobalAccess + && symbolToSortTextMap[getSymbolId(symbol)] === SortText.GlobalsOrKeywords + && symbolToSortTextMap[getSymbolId(symbolOrigin)] === SortText.AutoImportSuggestions) { + return false; + } + // Continue with origin symbol + symbol = symbolOrigin; // import m = /**/ <-- It can only access namespace (if typing import = x. this would get member symbols and not namespace) if (isInRightSideOfInternalImportEqualsDeclaration(location)) { diff --git a/tests/cases/fourslash/completionsImport_umdModules1_globalAccess.ts b/tests/cases/fourslash/completionsImport_umdModules1_globalAccess.ts new file mode 100644 index 0000000000000..3e2225ec8c12a --- /dev/null +++ b/tests/cases/fourslash/completionsImport_umdModules1_globalAccess.ts @@ -0,0 +1,33 @@ +/// + +// @filename: /package.json +//// { "dependencies": { "@types/classnames": "*" } } + +// @filename: /tsconfig.json +//// { "compilerOptions": { "allowUmdGlobalAccess": true } } + +// @filename: /node_modules/@types/classnames/package.json +//// { "name": "@types/classnames", "types": "index.d.ts" } + +// @filename: /node_modules/@types/classnames/index.d.ts +//// declare const classNames: () => string; +//// export = classNames; +//// export as namespace classNames; + +// @filename: /SomeReactComponent.tsx +//// import * as React from 'react'; +//// +//// const el1 =
foo
; + +goTo.marker("1"); + +verify.completions({ + includes: [{ + name: "classNames", + hasAction: undefined, // Asserts to have no actions + sortText: completion.SortText.GlobalsOrKeywords, + }], + preferences: { + includeCompletionsForModuleExports: true, + } +}); diff --git a/tests/cases/fourslash/completionsImport_umdModules2_moduleExports.ts b/tests/cases/fourslash/completionsImport_umdModules2_moduleExports.ts new file mode 100644 index 0000000000000..56db8733cbc49 --- /dev/null +++ b/tests/cases/fourslash/completionsImport_umdModules2_moduleExports.ts @@ -0,0 +1,34 @@ +/// + +// @filename: /package.json +//// { "dependencies": { "@types/classnames": "*" } } + +// @filename: /tsconfig.json +//// {} + +// @filename: /node_modules/@types/classnames/package.json +//// { "name": "@types/classnames", "types": "index.d.ts" } + +// @filename: /node_modules/@types/classnames/index.d.ts +//// declare const classNames: () => string; +//// export = classNames; +//// export as namespace classNames; + +// @filename: /SomeReactComponent.tsx +//// import * as React from 'react'; +//// +//// const el1 =
foo
; + +goTo.marker("1"); + +verify.completions({ + includes: [{ + name: "classNames", + hasAction: true, + source: "/node_modules/@types/classnames/index", + sortText: completion.SortText.AutoImportSuggestions, + }], + preferences: { + includeCompletionsForModuleExports: true, + } +}); diff --git a/tests/cases/fourslash/completionsImport_umdModules3_script.ts b/tests/cases/fourslash/completionsImport_umdModules3_script.ts new file mode 100644 index 0000000000000..cdcf6da2287ea --- /dev/null +++ b/tests/cases/fourslash/completionsImport_umdModules3_script.ts @@ -0,0 +1,32 @@ +/// + +// @filename: /package.json +//// { "dependencies": { "@types/classnames": "*" } } + +// @filename: /tsconfig.json +//// { "compilerOptions": { "module": "es2015" }} + +// @filename: /node_modules/@types/classnames/package.json +//// { "name": "@types/classnames", "types": "index.d.ts" } + +// @filename: /node_modules/@types/classnames/index.d.ts +//// declare const classNames: () => string; +//// export = classNames; +//// export as namespace classNames; + +// @filename: /SomeReactComponent.tsx +//// +//// const el1 =
foo
+ +goTo.marker("1"); + +verify.completions({ + includes: [{ + name: "classNames", + hasAction: undefined, // Asserts to have no actions + sortText: completion.SortText.GlobalsOrKeywords, + }], + preferences: { + includeCompletionsForModuleExports: true, + } +});