content: package com.google.javascript.clutz;
  
  import com.google.javascript.rhino.Node;
  import java.util.LinkedHashMap;
  import java.util.Map;
  import java.util.Map.Entry;
  import java.util.Set;
  
  /**
   * When a goog.module imports a symbol, there's an ambiguity about whether the symbol is from a
   * goog.provide style file or a goog.module style file. Normally this ambiguity is resolved by
   * consulting depgraphs, but a goog.module can declareLegacyNamespace, in which case it's exports
   * are in goog.provide style, but the depgraph says it's a goog.module. To resolve this ambiguity,
   * LegacyNamespaceReexportMapBuilder generates mappings from the goog.module style symbols to the
   * normally declared symbols, so DeclarationGenerator can produce aliases.
   */
  public class LegacyNamespaceReexportMapBuilder extends ImportBasedMapBuilder {
  
    @Override
    protected Map<String, String> build(
        String localModuleId, Node moduleBody, Set<String> googProvides) {
      Map<String, String> reexportMap = new LinkedHashMap<>();
      if (localModuleId == null) {
        return reexportMap;
      }
  
      if (!isLegacyNamespaceModule(moduleBody)) {
        return reexportMap;
      }
  
      for (Node statement : moduleBody.children()) {
        if (isWholeModuleExportAssignment(statement)) {
          // `exports = foo`
          String localVariableName = getExportsAssignmentRHS(statement);
  
          reexportMap.put(
              buildWholeModuleExportSymbolName(localModuleId),
              buildLocalSymbolName(localModuleId, localVariableName));
        } else if (isNamedExportAssignment(statement)) {
          // `exports.foo = foo`
          String localVariableName = getExportsAssignmentRHS(statement);
          String exportName = getNamedExportName(statement);
  
          reexportMap.put(
              buildNamedExportSymbolName(localModuleId, exportName),
              buildLocalSymbolName(localModuleId, localVariableName));
        } else if (isObjectLiteralExport(statement)) {
          // `exports = {foo, bar}`
          for (Entry<String, String> e :
              objectLiteralASTToStringMap(statement.getFirstChild().getChildAtIndex(1)).entrySet()) {
            String localVariableName = e.getValue();
            String exportName = e.getKey();
  
            reexportMap.put(
                buildNamedExportSymbolName(localModuleId, exportName),
                buildLocalSymbolName(localModuleId, localVariableName));
          }
        }
      }
      return reexportMap;
    }
  
    private boolean isLegacyNamespaceModule(Node moduleBody) {
      for (Node statement : moduleBody.children()) {
        if (isDeclareLegacyNamespaceStatement(statement)) {
          return true;
        }
      }
      return false;
    }
  
    /** Matches `goog.module.declareLegacyNamespace();` */
    protected boolean isDeclareLegacyNamespaceStatement(Node statement) {
      if (!statement.isExprResult()) {
        return false;
      }
  
      if (!statement.getFirstChild().isCall()) {
        return false;
      }
  
      Node callBody = statement.getFirstFirstChild();
  
      return callBody.matchesQualifiedName("goog.module.declareLegacyNamespace");
    }
  }
  