Skip to content

Commit 290af69

Browse files
authored
Filter out global keywords of UMD module export declarations in completion providing auto import suggestions (microsoft#42141)
* Add AutoImportSuggestions for UMD module export declarations instead of global keywords * Add test for scripts * Add more comments * Provide auto import suggestion only for modules and not scripts * PR review #1 * PR review #1
1 parent 154f209 commit 290af69

4 files changed

+116
-1
lines changed

src/services/completions.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,7 @@ namespace ts.Completions {
855855
host: LanguageServiceHost
856856
): CompletionData | Request | undefined {
857857
const typeChecker = program.getTypeChecker();
858+
const compilerOptions = program.getCompilerOptions();
858859

859860
let start = timestamp();
860861
let currentToken = getTokenAtPosition(sourceFile, position); // TODO: GH#15853
@@ -1519,7 +1520,22 @@ namespace ts.Completions {
15191520
return false;
15201521
}
15211522

1522-
symbol = skipAlias(symbol, typeChecker);
1523+
// External modules can have global export declarations that will be
1524+
// available as global keywords in all scopes. But if the external module
1525+
// already has an explicit export and user only wants to user explicit
1526+
// module imports then the global keywords will be filtered out so auto
1527+
// import suggestions will win in the completion
1528+
const symbolOrigin = skipAlias(symbol, typeChecker);
1529+
// We only want to filter out the global keywords
1530+
// Auto Imports are not available for scripts so this conditional is always false
1531+
if (!!sourceFile.externalModuleIndicator
1532+
&& !compilerOptions.allowUmdGlobalAccess
1533+
&& symbolToSortTextMap[getSymbolId(symbol)] === SortText.GlobalsOrKeywords
1534+
&& symbolToSortTextMap[getSymbolId(symbolOrigin)] === SortText.AutoImportSuggestions) {
1535+
return false;
1536+
}
1537+
// Continue with origin symbol
1538+
symbol = symbolOrigin;
15231539

15241540
// import m = /**/ <-- It can only access namespace (if typing import = x. this would get member symbols and not namespace)
15251541
if (isInRightSideOfInternalImportEqualsDeclaration(location)) {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/// <reference path="./fourslash.ts" />
2+
3+
// @filename: /package.json
4+
//// { "dependencies": { "@types/classnames": "*" } }
5+
6+
// @filename: /tsconfig.json
7+
//// { "compilerOptions": { "allowUmdGlobalAccess": true } }
8+
9+
// @filename: /node_modules/@types/classnames/package.json
10+
//// { "name": "@types/classnames", "types": "index.d.ts" }
11+
12+
// @filename: /node_modules/@types/classnames/index.d.ts
13+
//// declare const classNames: () => string;
14+
//// export = classNames;
15+
//// export as namespace classNames;
16+
17+
// @filename: /SomeReactComponent.tsx
18+
//// import * as React from 'react';
19+
////
20+
//// const el1 = <div className={class/*1*/}>foo</div>;
21+
22+
goTo.marker("1");
23+
24+
verify.completions({
25+
includes: [{
26+
name: "classNames",
27+
hasAction: undefined, // Asserts to have no actions
28+
sortText: completion.SortText.GlobalsOrKeywords,
29+
}],
30+
preferences: {
31+
includeCompletionsForModuleExports: true,
32+
}
33+
});
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/// <reference path="./fourslash.ts" />
2+
3+
// @filename: /package.json
4+
//// { "dependencies": { "@types/classnames": "*" } }
5+
6+
// @filename: /tsconfig.json
7+
//// {}
8+
9+
// @filename: /node_modules/@types/classnames/package.json
10+
//// { "name": "@types/classnames", "types": "index.d.ts" }
11+
12+
// @filename: /node_modules/@types/classnames/index.d.ts
13+
//// declare const classNames: () => string;
14+
//// export = classNames;
15+
//// export as namespace classNames;
16+
17+
// @filename: /SomeReactComponent.tsx
18+
//// import * as React from 'react';
19+
////
20+
//// const el1 = <div className={class/*1*/}>foo</div>;
21+
22+
goTo.marker("1");
23+
24+
verify.completions({
25+
includes: [{
26+
name: "classNames",
27+
hasAction: true,
28+
source: "/node_modules/@types/classnames/index",
29+
sortText: completion.SortText.AutoImportSuggestions,
30+
}],
31+
preferences: {
32+
includeCompletionsForModuleExports: true,
33+
}
34+
});
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/// <reference path="./fourslash.ts" />
2+
3+
// @filename: /package.json
4+
//// { "dependencies": { "@types/classnames": "*" } }
5+
6+
// @filename: /tsconfig.json
7+
//// { "compilerOptions": { "module": "es2015" }}
8+
9+
// @filename: /node_modules/@types/classnames/package.json
10+
//// { "name": "@types/classnames", "types": "index.d.ts" }
11+
12+
// @filename: /node_modules/@types/classnames/index.d.ts
13+
//// declare const classNames: () => string;
14+
//// export = classNames;
15+
//// export as namespace classNames;
16+
17+
// @filename: /SomeReactComponent.tsx
18+
////
19+
//// const el1 = <div className={class/*1*/}>foo</div>
20+
21+
goTo.marker("1");
22+
23+
verify.completions({
24+
includes: [{
25+
name: "classNames",
26+
hasAction: undefined, // Asserts to have no actions
27+
sortText: completion.SortText.GlobalsOrKeywords,
28+
}],
29+
preferences: {
30+
includeCompletionsForModuleExports: true,
31+
}
32+
});

0 commit comments

Comments
 (0)