diff --git a/src/services/completions.ts b/src/services/completions.ts
index 66a1e2cc72e..d7aa66bdf4c 100644
--- a/src/services/completions.ts
+++ b/src/services/completions.ts
@@ -1349,18 +1349,17 @@ namespace ts.Completions {
}
for (const symbol of typeChecker.getExportsOfModule(moduleSymbol)) {
- // If `symbol.parent !== ...`, this is an `export * from "foo"` re-export. Those don't create new symbols.
- if (typeChecker.getMergedSymbol(symbol.parent!) !== resolvedModuleSymbol) {
- continue;
- }
// If this is `export { _break as break };` (a keyword) -- skip this and prefer the keyword completion.
if (some(symbol.declarations, d => isExportSpecifier(d) && !!d.propertyName && isIdentifierANonContextualKeyword(d.name))) {
continue;
}
+ // If `symbol.parent !== moduleSymbol`, this is an `export * from "foo"` re-export. Those don't create new symbols.
+ const isExportStarFromReExport = typeChecker.getMergedSymbol(symbol.parent!) !== resolvedModuleSymbol;
// 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).
- if (some(symbol.declarations, d => isExportSpecifier(d) && !d.propertyName && !!d.parent.parent.moduleSpecifier)) {
- // Walk the export chain back one module (step 1 or 2 in diagrammed example)
- const nearestExportSymbolId = getSymbolId(Debug.assertDefined(getNearestExportSymbol(symbol)));
+ if (isExportStarFromReExport || some(symbol.declarations, d => isExportSpecifier(d) && !d.propertyName && !!d.parent.parent.moduleSpecifier)) {
+ // Walk the export chain back one module (step 1 or 2 in diagrammed example).
+ // Or, in the case of `export * from "foo"`, `symbol` already points to the original export, so just use that.
+ const nearestExportSymbolId = getSymbolId(isExportStarFromReExport ? symbol : Debug.assertDefined(getNearestExportSymbol(symbol)));
const symbolHasBeenSeen = !!symbolToOriginInfoMap[nearestExportSymbolId] || aliasesToAlreadyIncludedSymbols.has(nearestExportSymbolId.toString());
if (!symbolHasBeenSeen) {
aliasesToReturnIfOriginalsAreMissing.set(nearestExportSymbolId.toString(), { alias: symbol, moduleSymbol });
diff --git a/tests/cases/fourslash/completionsImport_filteredByPackageJson_reexport3.ts b/tests/cases/fourslash/completionsImport_filteredByPackageJson_reexport3.ts
new file mode 100644
index 00000000000..8533461e0b8
--- /dev/null
+++ b/tests/cases/fourslash/completionsImport_filteredByPackageJson_reexport3.ts
@@ -0,0 +1,48 @@
+///
+
+//@noEmit: true
+
+//@Filename: /package.json
+////{
+//// "dependencies": {
+//// "b": "*",
+//// }
+////}
+
+//@Filename: /node_modules/a/index.d.ts
+////export const foo = 0;
+
+//@Filename: /node_modules/a/package.json
+////{
+//// "name": "a",
+//// "types": "./index.d.ts"
+////}
+
+//@Filename: /node_modules/b/index.d.ts
+////export * from "a";
+
+//@Filename: /node_modules/b/package.json
+////{
+//// "name": "b",
+//// "types": "./index.d.ts"
+////}
+
+//@Filename: /src/index.ts
+////fo/**/
+
+verify.completions({
+ marker: test.marker(""),
+ includes: [
+ completion.undefinedVarEntry,
+ {
+ name: "foo",
+ source: "/node_modules/b/index",
+ hasAction: true,
+ sortText: completion.SortText.AutoImportSuggestions
+ },
+ ...completion.statementKeywordsWithTypes
+ ],
+ preferences: {
+ includeCompletionsForModuleExports: true
+ }
+});
diff --git a/tests/cases/fourslash/completionsImport_filteredByPackageJson_reexport4.ts b/tests/cases/fourslash/completionsImport_filteredByPackageJson_reexport4.ts
new file mode 100644
index 00000000000..83ac6526b25
--- /dev/null
+++ b/tests/cases/fourslash/completionsImport_filteredByPackageJson_reexport4.ts
@@ -0,0 +1,57 @@
+///
+
+//@noEmit: true
+
+//@Filename: /package.json
+////{
+//// "dependencies": {
+//// "c": "*",
+//// }
+////}
+
+//@Filename: /node_modules/a/index.d.ts
+////export const foo = 0;
+
+//@Filename: /node_modules/a/package.json
+////{
+//// "name": "a",
+//// "types": "./index.d.ts"
+////}
+
+//@Filename: /node_modules/b/index.d.ts
+////export * from "a";
+
+//@Filename: /node_modules/b/package.json
+////{
+//// "name": "b",
+//// "types": "./index.d.ts"
+////}
+
+//@Filename: /node_modules/c/index.d.ts
+////export * from "a";
+
+//@Filename: /node_modules/c/package.json
+////{
+//// "name": "c",
+//// "types": "./index.d.ts"
+////}
+
+//@Filename: /src/index.ts
+////fo/**/
+
+verify.completions({
+ marker: test.marker(""),
+ includes: [
+ completion.undefinedVarEntry,
+ {
+ name: "foo",
+ source: "/node_modules/c/index",
+ hasAction: true,
+ sortText: completion.SortText.AutoImportSuggestions
+ },
+ ...completion.statementKeywordsWithTypes
+ ],
+ preferences: {
+ includeCompletionsForModuleExports: true
+ }
+});