@@ -5161,6 +5161,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
5161
5161
interface ExportCollisionTracker {
5162
5162
specifierText: string;
5163
5163
exportsWithDuplicate?: ExportDeclaration[];
5164
+ isTypeOnly?: boolean;
5164
5165
}
5165
5166
5166
5167
type ExportCollisionTrackerTable = UnderscoreEscapedMap<ExportCollisionTracker>;
@@ -5169,7 +5170,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
5169
5170
* Extends one symbol table with another while collecting information on name collisions for error message generation into the `lookupTable` argument
5170
5171
* Not passing `lookupTable` and `exportNode` disables this collection, and just extends the tables
5171
5172
*/
5172
- function extendExportSymbols(target: SymbolTable, source: SymbolTable | undefined, lookupTable?: ExportCollisionTrackerTable, exportNode?: ExportDeclaration) {
5173
+ function extendExportSymbols(target: SymbolTable, source: SymbolTable | undefined, lookupTable?: ExportCollisionTrackerTable, exportNode?: ExportDeclaration, isTypeOnly?: boolean ) {
5173
5174
if (!source) return;
5174
5175
source.forEach((sourceSymbol, id) => {
5175
5176
if (id === InternalSymbolName.Default) return;
@@ -5179,17 +5180,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
5179
5180
target.set(id, sourceSymbol);
5180
5181
if (lookupTable && exportNode) {
5181
5182
lookupTable.set(id, {
5182
- specifierText: getTextOfNode(exportNode.moduleSpecifier!)
5183
+ specifierText: getTextOfNode(exportNode.moduleSpecifier!),
5184
+ isTypeOnly,
5183
5185
});
5184
5186
}
5185
5187
}
5186
- else if (lookupTable && exportNode && targetSymbol && resolveSymbol(targetSymbol) !== resolveSymbol(sourceSymbol) ) {
5188
+ else if (lookupTable && exportNode && targetSymbol) {
5187
5189
const collisionTracker = lookupTable.get(id)!;
5188
- if (!collisionTracker.exportsWithDuplicate) {
5189
- collisionTracker.exportsWithDuplicate = [exportNode];
5190
- }
5191
- else {
5192
- collisionTracker.exportsWithDuplicate.push(exportNode);
5190
+ collisionTracker.isTypeOnly = collisionTracker.isTypeOnly && isTypeOnly;
5191
+ if (resolveSymbol(targetSymbol) !== resolveSymbol(sourceSymbol)) {
5192
+ if (!collisionTracker.exportsWithDuplicate) {
5193
+ collisionTracker.exportsWithDuplicate = [exportNode];
5194
+ }
5195
+ else {
5196
+ collisionTracker.exportsWithDuplicate.push(exportNode);
5197
+ }
5193
5198
}
5194
5199
}
5195
5200
});
@@ -5198,30 +5203,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
5198
5203
function getExportsOfModuleWorker(moduleSymbol: Symbol) {
5199
5204
const visitedSymbols: Symbol[] = [];
5200
5205
let typeOnlyExportStarMap: UnderscoreEscapedMap<ExportDeclaration & { readonly isTypeOnly: true }> | undefined;
5201
- const nonTypeOnlyNames = new Set<__String>();
5202
5206
5203
5207
// A module defined by an 'export=' consists of one export that needs to be resolved
5204
5208
moduleSymbol = resolveExternalModuleSymbol(moduleSymbol);
5205
- const exports = visit(moduleSymbol) || emptySymbols;
5206
-
5207
- if (typeOnlyExportStarMap) {
5208
- nonTypeOnlyNames.forEach(name => typeOnlyExportStarMap!.delete(name));
5209
- }
5210
5209
5211
5210
return {
5212
- exports,
5211
+ exports: visit(moduleSymbol) || emptySymbols ,
5213
5212
typeOnlyExportStarMap,
5214
5213
};
5215
5214
5216
5215
// The ES6 spec permits export * declarations in a module to circularly reference the module itself. For example,
5217
5216
// module 'a' can 'export * from "b"' and 'b' can 'export * from "a"' without error.
5218
5217
function visit(symbol: Symbol | undefined, exportStar?: ExportDeclaration, isTypeOnly?: boolean): SymbolTable | undefined {
5219
- if (!isTypeOnly && symbol?.exports) {
5220
- // Add non-type-only names before checking if we've visited this module,
5221
- // because we might have visited it via an 'export type *', and visiting
5222
- // again with 'export *' will override the type-onlyness of its exports.
5223
- symbol.exports.forEach((_, name) => nonTypeOnlyNames.add(name));
5224
- }
5225
5218
if (!(symbol && symbol.exports && pushIfUnique(visitedSymbols, symbol))) {
5226
5219
return;
5227
5220
}
@@ -5235,16 +5228,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
5235
5228
if (exportStars.declarations) {
5236
5229
for (const node of exportStars.declarations) {
5237
5230
const resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier!);
5238
- const exportedSymbols = visit(resolvedModule, node as ExportDeclaration, isTypeOnly || (node as ExportDeclaration).isTypeOnly);
5231
+ const nestedExportsAreTypeOnly = isTypeOnly || (node as ExportDeclaration).isTypeOnly;
5232
+ const exportedSymbols = visit(resolvedModule, node as ExportDeclaration, nestedExportsAreTypeOnly);
5239
5233
extendExportSymbols(
5240
5234
nestedSymbols,
5241
5235
exportedSymbols,
5242
5236
lookupTable,
5243
- node as ExportDeclaration
5237
+ node as ExportDeclaration,
5238
+ nestedExportsAreTypeOnly,
5244
5239
);
5245
5240
}
5246
5241
}
5247
5242
lookupTable.forEach(({ exportsWithDuplicate }, id) => {
5243
+ if (typeOnlyExportStarMap && !isTypeOnly && exportsWithDuplicate?.length) {
5244
+ typeOnlyExportStarMap.delete(id);
5245
+ }
5248
5246
// It's not an error if the file with multiple `export *`s with duplicate names exports a member with that name itself
5249
5247
if (id === "export=" || !(exportsWithDuplicate && exportsWithDuplicate.length) || symbols.has(id)) {
5250
5248
return;
0 commit comments