Skip to content

Commit de8ef32

Browse files
committed
Fix and add tests for export * re-exports
1 parent fbb05d5 commit de8ef32

File tree

3 files changed

+111
-7
lines changed

3 files changed

+111
-7
lines changed

src/services/completions.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,18 +1334,17 @@ namespace ts.Completions {
13341334
}
13351335

13361336
for (const symbol of typeChecker.getExportsOfModule(moduleSymbol)) {
1337-
// If `symbol.parent !== ...`, this is an `export * from "foo"` re-export. Those don't create new symbols.
1338-
if (typeChecker.getMergedSymbol(symbol.parent!) !== resolvedModuleSymbol) {
1339-
continue;
1340-
}
13411337
// If this is `export { _break as break };` (a keyword) -- skip this and prefer the keyword completion.
13421338
if (some(symbol.declarations, d => isExportSpecifier(d) && !!d.propertyName && isIdentifierANonContextualKeyword(d.name))) {
13431339
continue;
13441340
}
1341+
// If `symbol.parent !== moduleSymbol`, this is an `export * from "foo"` re-export. Those don't create new symbols.
1342+
const isExportStarFromReExport = typeChecker.getMergedSymbol(symbol.parent!) !== resolvedModuleSymbol;
13451343
// If `!!d.parent.parent.moduleSpecifier`, this is `export { foo } from "foo"` re-export, which creates a new symbol (thus isn't caught by the first check).
1346-
if (some(symbol.declarations, d => isExportSpecifier(d) && !d.propertyName && !!d.parent.parent.moduleSpecifier)) {
1347-
// Walk the export chain back one module (step 1 or 2 in diagrammed example)
1348-
const nearestExportSymbolId = getSymbolId(Debug.assertDefined(getNearestExportSymbol(symbol)));
1344+
if (isExportStarFromReExport || some(symbol.declarations, d => isExportSpecifier(d) && !d.propertyName && !!d.parent.parent.moduleSpecifier)) {
1345+
// Walk the export chain back one module (step 1 or 2 in diagrammed example).
1346+
// Or, in the case of `export * from "foo"`, `symbol` already points to the original export, so just use that.
1347+
const nearestExportSymbolId = getSymbolId(isExportStarFromReExport ? symbol : Debug.assertDefined(getNearestExportSymbol(symbol)));
13491348
const symbolHasBeenSeen = !!symbolToOriginInfoMap[nearestExportSymbolId] || aliasesToAlreadyIncludedSymbols.has(nearestExportSymbolId.toString());
13501349
if (!symbolHasBeenSeen) {
13511350
aliasesToReturnIfOriginalsAreMissing.set(nearestExportSymbolId.toString(), { alias: symbol, moduleSymbol });
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
//@noEmit: true
4+
5+
//@Filename: /package.json
6+
////{
7+
//// "dependencies": {
8+
//// "b": "*",
9+
//// }
10+
////}
11+
12+
//@Filename: /node_modules/a/index.d.ts
13+
////export const foo = 0;
14+
15+
//@Filename: /node_modules/a/package.json
16+
////{
17+
//// "name": "a",
18+
//// "types": "./index.d.ts"
19+
////}
20+
21+
//@Filename: /node_modules/b/index.d.ts
22+
////export * from "a";
23+
24+
//@Filename: /node_modules/b/package.json
25+
////{
26+
//// "name": "b",
27+
//// "types": "./index.d.ts"
28+
////}
29+
30+
//@Filename: /src/index.ts
31+
////fo/**/
32+
33+
verify.completions({
34+
marker: test.marker(""),
35+
includes: [
36+
completion.undefinedVarEntry,
37+
{
38+
name: "foo",
39+
source: "/node_modules/b/index",
40+
hasAction: true,
41+
sortText: completion.SortText.AutoImportSuggestions
42+
},
43+
...completion.statementKeywordsWithTypes
44+
],
45+
preferences: {
46+
includeCompletionsForModuleExports: true
47+
}
48+
});
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
//@noEmit: true
4+
5+
//@Filename: /package.json
6+
////{
7+
//// "dependencies": {
8+
//// "c": "*",
9+
//// }
10+
////}
11+
12+
//@Filename: /node_modules/a/index.d.ts
13+
////export const foo = 0;
14+
15+
//@Filename: /node_modules/a/package.json
16+
////{
17+
//// "name": "a",
18+
//// "types": "./index.d.ts"
19+
////}
20+
21+
//@Filename: /node_modules/b/index.d.ts
22+
////export * from "a";
23+
24+
//@Filename: /node_modules/b/package.json
25+
////{
26+
//// "name": "b",
27+
//// "types": "./index.d.ts"
28+
////}
29+
30+
//@Filename: /node_modules/c/index.d.ts
31+
////export * from "a";
32+
33+
//@Filename: /node_modules/c/package.json
34+
////{
35+
//// "name": "c",
36+
//// "types": "./index.d.ts"
37+
////}
38+
39+
//@Filename: /src/index.ts
40+
////fo/**/
41+
42+
verify.completions({
43+
marker: test.marker(""),
44+
includes: [
45+
completion.undefinedVarEntry,
46+
{
47+
name: "foo",
48+
source: "/node_modules/c/index",
49+
hasAction: true,
50+
sortText: completion.SortText.AutoImportSuggestions
51+
},
52+
...completion.statementKeywordsWithTypes
53+
],
54+
preferences: {
55+
includeCompletionsForModuleExports: true
56+
}
57+
});

0 commit comments

Comments
 (0)