function visitExportDeclaration()

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;
      }