Skip to content

Commit

Permalink
Update API
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewbranch committed Jan 12, 2023
1 parent 08701ac commit 4a8519f
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 31 deletions.
44 changes: 21 additions & 23 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5161,6 +5161,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
interface ExportCollisionTracker {
specifierText: string;
exportsWithDuplicate?: ExportDeclaration[];
isTypeOnly?: boolean;
}

type ExportCollisionTrackerTable = UnderscoreEscapedMap<ExportCollisionTracker>;
Expand All @@ -5169,7 +5170,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
* Extends one symbol table with another while collecting information on name collisions for error message generation into the `lookupTable` argument
* Not passing `lookupTable` and `exportNode` disables this collection, and just extends the tables
*/
function extendExportSymbols(target: SymbolTable, source: SymbolTable | undefined, lookupTable?: ExportCollisionTrackerTable, exportNode?: ExportDeclaration) {
function extendExportSymbols(target: SymbolTable, source: SymbolTable | undefined, lookupTable?: ExportCollisionTrackerTable, exportNode?: ExportDeclaration, isTypeOnly?: boolean) {
if (!source) return;
source.forEach((sourceSymbol, id) => {
if (id === InternalSymbolName.Default) return;
Expand All @@ -5179,17 +5180,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
target.set(id, sourceSymbol);
if (lookupTable && exportNode) {
lookupTable.set(id, {
specifierText: getTextOfNode(exportNode.moduleSpecifier!)
specifierText: getTextOfNode(exportNode.moduleSpecifier!),
isTypeOnly,
});
}
}
else if (lookupTable && exportNode && targetSymbol && resolveSymbol(targetSymbol) !== resolveSymbol(sourceSymbol)) {
else if (lookupTable && exportNode && targetSymbol) {
const collisionTracker = lookupTable.get(id)!;
if (!collisionTracker.exportsWithDuplicate) {
collisionTracker.exportsWithDuplicate = [exportNode];
}
else {
collisionTracker.exportsWithDuplicate.push(exportNode);
collisionTracker.isTypeOnly = collisionTracker.isTypeOnly && isTypeOnly;
if (resolveSymbol(targetSymbol) !== resolveSymbol(sourceSymbol)) {
if (!collisionTracker.exportsWithDuplicate) {
collisionTracker.exportsWithDuplicate = [exportNode];
}
else {
collisionTracker.exportsWithDuplicate.push(exportNode);
}
}
}
});
Expand All @@ -5198,30 +5203,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
function getExportsOfModuleWorker(moduleSymbol: Symbol) {
const visitedSymbols: Symbol[] = [];
let typeOnlyExportStarMap: UnderscoreEscapedMap<ExportDeclaration & { readonly isTypeOnly: true }> | undefined;
const nonTypeOnlyNames = new Set<__String>();

// A module defined by an 'export=' consists of one export that needs to be resolved
moduleSymbol = resolveExternalModuleSymbol(moduleSymbol);
const exports = visit(moduleSymbol) || emptySymbols;

if (typeOnlyExportStarMap) {
nonTypeOnlyNames.forEach(name => typeOnlyExportStarMap!.delete(name));
}

return {
exports,
exports: visit(moduleSymbol) || emptySymbols,
typeOnlyExportStarMap,
};

// The ES6 spec permits export * declarations in a module to circularly reference the module itself. For example,
// module 'a' can 'export * from "b"' and 'b' can 'export * from "a"' without error.
function visit(symbol: Symbol | undefined, exportStar?: ExportDeclaration, isTypeOnly?: boolean): SymbolTable | undefined {
if (!isTypeOnly && symbol?.exports) {
// Add non-type-only names before checking if we've visited this module,
// because we might have visited it via an 'export type *', and visiting
// again with 'export *' will override the type-onlyness of its exports.
symbol.exports.forEach((_, name) => nonTypeOnlyNames.add(name));
}
if (!(symbol && symbol.exports && pushIfUnique(visitedSymbols, symbol))) {
return;
}
Expand All @@ -5235,16 +5228,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (exportStars.declarations) {
for (const node of exportStars.declarations) {
const resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier!);
const exportedSymbols = visit(resolvedModule, node as ExportDeclaration, isTypeOnly || (node as ExportDeclaration).isTypeOnly);
const nestedExportsAreTypeOnly = isTypeOnly || (node as ExportDeclaration).isTypeOnly;
const exportedSymbols = visit(resolvedModule, node as ExportDeclaration, nestedExportsAreTypeOnly);
extendExportSymbols(
nestedSymbols,
exportedSymbols,
lookupTable,
node as ExportDeclaration
node as ExportDeclaration,
nestedExportsAreTypeOnly,
);
}
}
lookupTable.forEach(({ exportsWithDuplicate }, id) => {
if (typeOnlyExportStarMap && !isTypeOnly && exportsWithDuplicate?.length) {
typeOnlyExportStarMap.delete(id);
}
// It's not an error if the file with multiple `export *`s with duplicate names exports a member with that name itself
if (id === "export=" || !(exportsWithDuplicate && exportsWithDuplicate.length) || symbols.has(id)) {
return;
Expand Down
18 changes: 14 additions & 4 deletions tests/baselines/reference/api/tsserverlibrary.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5713,8 +5713,8 @@ declare namespace ts {
readonly name: Identifier;
}
type ImportOrExportSpecifier = ImportSpecifier | ExportSpecifier;
type TypeOnlyCompatibleAliasDeclaration = ImportClause | ImportEqualsDeclaration | NamespaceImport | ImportOrExportSpecifier;
type TypeOnlyAliasDeclaration = ImportClause & {
type TypeOnlyCompatibleAliasDeclaration = ImportClause | ImportEqualsDeclaration | NamespaceImport | ImportOrExportSpecifier | ExportDeclaration | NamespaceExport;
type TypeOnlyImportDeclaration = ImportClause & {
readonly isTypeOnly: true;
readonly name: Identifier;
} | ImportEqualsDeclaration & {
Expand All @@ -5731,15 +5731,23 @@ declare namespace ts {
readonly isTypeOnly: true;
};
};
}) | ExportSpecifier & ({
});
type TypeOnlyExportDeclaration = ExportSpecifier & ({
readonly isTypeOnly: true;
} | {
readonly parent: NamedExports & {
readonly parent: ExportDeclaration & {
readonly isTypeOnly: true;
};
};
});
}) | ExportDeclaration & {
readonly isTypeOnly: true;
} | NamespaceExport & {
readonly parent: ExportDeclaration & {
readonly isTypeOnly: true;
};
};
type TypeOnlyAliasDeclaration = TypeOnlyImportDeclaration | TypeOnlyExportDeclaration;
/**
* This is either an `export =` or an `export default` declaration.
* Unless `isExportEquals` is set, this node was parsed as an `export default`.
Expand Down Expand Up @@ -8732,6 +8740,8 @@ declare namespace ts {
function isTemplateLiteralToken(node: Node): node is TemplateLiteralToken;
function isTemplateMiddleOrTemplateTail(node: Node): node is TemplateMiddle | TemplateTail;
function isImportOrExportSpecifier(node: Node): node is ImportSpecifier | ExportSpecifier;
function isTypeOnlyImportDeclaration(node: Node): node is TypeOnlyImportDeclaration;
function isTypeOnlyExportDeclaration(node: Node): node is TypeOnlyExportDeclaration;
function isTypeOnlyImportOrExportDeclaration(node: Node): node is TypeOnlyAliasDeclaration;
function isAssertionKey(node: Node): node is AssertionKey;
function isStringTextContainingNode(node: Node): node is StringLiteral | TemplateLiteralToken;
Expand Down
18 changes: 14 additions & 4 deletions tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1778,8 +1778,8 @@ declare namespace ts {
readonly name: Identifier;
}
type ImportOrExportSpecifier = ImportSpecifier | ExportSpecifier;
type TypeOnlyCompatibleAliasDeclaration = ImportClause | ImportEqualsDeclaration | NamespaceImport | ImportOrExportSpecifier;
type TypeOnlyAliasDeclaration = ImportClause & {
type TypeOnlyCompatibleAliasDeclaration = ImportClause | ImportEqualsDeclaration | NamespaceImport | ImportOrExportSpecifier | ExportDeclaration | NamespaceExport;
type TypeOnlyImportDeclaration = ImportClause & {
readonly isTypeOnly: true;
readonly name: Identifier;
} | ImportEqualsDeclaration & {
Expand All @@ -1796,15 +1796,23 @@ declare namespace ts {
readonly isTypeOnly: true;
};
};
}) | ExportSpecifier & ({
});
type TypeOnlyExportDeclaration = ExportSpecifier & ({
readonly isTypeOnly: true;
} | {
readonly parent: NamedExports & {
readonly parent: ExportDeclaration & {
readonly isTypeOnly: true;
};
};
});
}) | ExportDeclaration & {
readonly isTypeOnly: true;
} | NamespaceExport & {
readonly parent: ExportDeclaration & {
readonly isTypeOnly: true;
};
};
type TypeOnlyAliasDeclaration = TypeOnlyImportDeclaration | TypeOnlyExportDeclaration;
/**
* This is either an `export =` or an `export default` declaration.
* Unless `isExportEquals` is set, this node was parsed as an `export default`.
Expand Down Expand Up @@ -4797,6 +4805,8 @@ declare namespace ts {
function isTemplateLiteralToken(node: Node): node is TemplateLiteralToken;
function isTemplateMiddleOrTemplateTail(node: Node): node is TemplateMiddle | TemplateTail;
function isImportOrExportSpecifier(node: Node): node is ImportSpecifier | ExportSpecifier;
function isTypeOnlyImportDeclaration(node: Node): node is TypeOnlyImportDeclaration;
function isTypeOnlyExportDeclaration(node: Node): node is TypeOnlyExportDeclaration;
function isTypeOnlyImportOrExportDeclaration(node: Node): node is TypeOnlyAliasDeclaration;
function isAssertionKey(node: Node): node is AssertionKey;
function isStringTextContainingNode(node: Node): node is StringLiteral | TemplateLiteralToken;
Expand Down

0 comments on commit 4a8519f

Please sign in to comment.