in src/jsdoc_transformer.ts [1032:1110]
function visitExportDeclaration(exportDecl: ts.ExportDeclaration): ts.Node|ts.Node[] {
const importedModuleSymbol = exportDecl.moduleSpecifier &&
typeChecker.getSymbolAtLocation(exportDecl.moduleSpecifier)!;
if (importedModuleSymbol) {
// requireType all explicitly imported modules, so that symbols can be referenced and
// type only modules are usable from type declarations.
moduleTypeTranslator.requireType(
exportDecl.moduleSpecifier!, (exportDecl.moduleSpecifier as ts.StringLiteral).text,
importedModuleSymbol,
/* default import? */ false);
}
const typesToExport: Array<[string, ts.Symbol]> = [];
if (!exportDecl.exportClause) {
// export * from '...'
// Resolve the * into all value symbols exported, and update the export declaration.
// Explicitly spelled out exports (i.e. the exports of the current module) take precedence
// over implicit ones from export *. Use the current module's exports to filter.
const currentModuleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
const currentModuleExports = currentModuleSymbol && currentModuleSymbol.exports;
if (!importedModuleSymbol) {
moduleTypeTranslator.error(exportDecl, `export * without module symbol`);
return exportDecl;
}
const exportedSymbols = typeChecker.getExportsOfModule(importedModuleSymbol);
const exportSpecifiers: ts.ExportSpecifier[] = [];
for (const sym of exportedSymbols) {
if (currentModuleExports && currentModuleExports.has(sym.escapedName)) continue;
// We might have already generated an export for the given symbol.
if (expandedStarImports.has(sym.name)) continue;
expandedStarImports.add(sym.name);
// Only create an export specifier for values that are exported. For types, the code
// below creates specific export statements that match Closure's expectations.
if (shouldEmitValueExportForSymbol(sym)) {
exportSpecifiers.push(ts.factory.createExportSpecifier(
/* isTypeOnly */ false, undefined, sym.name));
} else {
typesToExport.push([sym.name, sym]);
}
}
const isTypeOnlyExport = false;
exportDecl = ts.factory.updateExportDeclaration(
exportDecl, exportDecl.decorators, exportDecl.modifiers,
isTypeOnlyExport, ts.factory.createNamedExports(exportSpecifiers),
exportDecl.moduleSpecifier, exportDecl.assertClause);
} else if (ts.isNamedExports(exportDecl.exportClause)) {
// export {a, b, c} from 'abc';
for (const exp of exportDecl.exportClause.elements) {
const exportedName = transformerUtil.getIdentifierText(exp.name);
typesToExport.push(
[exportedName, moduleTypeTranslator.mustGetSymbolAtLocation(exp.name)]);
}
}
// Do not emit typedef re-exports in untyped mode.
if (host.untyped) return exportDecl;
const result: ts.Node[] = [exportDecl];
for (const [exportedName, sym] of typesToExport) {
let aliasedSymbol = sym;
if (sym.flags & ts.SymbolFlags.Alias) {
aliasedSymbol = typeChecker.getAliasedSymbol(sym);
}
const isTypeAlias = (aliasedSymbol.flags & ts.SymbolFlags.Value) === 0 &&
(aliasedSymbol.flags & (ts.SymbolFlags.TypeAlias | ts.SymbolFlags.Interface)) !== 0;
if (!isTypeAlias) continue;
const typeName =
moduleTypeTranslator.symbolsToAliasedNames.get(aliasedSymbol) || aliasedSymbol.name;
const stmt = ts.factory.createExpressionStatement(
ts.factory.createPropertyAccessExpression(
ts.factory.createIdentifier('exports'), exportedName));
addCommentOn(stmt, [{tagName: 'typedef', type: '!' + typeName}]);
ts.addSyntheticTrailingComment(
stmt, ts.SyntaxKind.SingleLineCommentTrivia, ' re-export typedef', true);
result.push(stmt);
}
return result;
}