All files / transpiler/output/headers ExternalTypeHeaderBuilder.ts

100% Statements 8/8
100% Branches 8/8
100% Functions 1/1
100% Lines 8/8

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66                                                                          116x     116x   12x     12x 15x             11x 10x           116x          
/**
 * ExternalTypeHeaderBuilder
 * Builds mapping from external type names to their C header include directives.
 *
 * Issue #589: Extracted from Transpiler.buildExternalTypeHeaders()
 * Issue #497: Enables header generation to include original C headers instead of
 * generating conflicting forward declarations for types like anonymous struct typedefs.
 */
 
import ESymbolKind from "../../../utils/types/ESymbolKind";
import ISymbol from "../../../utils/types/ISymbol";
 
/**
 * Interface for accessing symbols by file path
 */
interface ISymbolSource {
  getSymbolsByFile(filePath: string): ISymbol[];
}
 
/**
 * Builds mapping from external type names to their C header include directives
 */
class ExternalTypeHeaderBuilder {
  /**
   * Build a map from external type names to their C header include directives.
   *
   * This enables header generation to include the original C headers instead of
   * generating conflicting forward declarations for types like anonymous struct typedefs.
   *
   * @param headerIncludeDirectives Map from header file paths to their include directives
   * @param symbolSource Source for retrieving symbols by file path (typically SymbolTable)
   * @returns Map from type names to include directives (e.g., "MyStruct" -> '#include "mystruct.h"')
   */
  static build(
    headerIncludeDirectives: ReadonlyMap<string, string>,
    symbolSource: ISymbolSource,
  ): Map<string, string> {
    const typeHeaders = new Map<string, string>();
 
    // Check each header we have an include directive for
    for (const [headerPath, directive] of headerIncludeDirectives) {
      // Get all symbols defined in this header
      const symbols = symbolSource.getSymbolsByFile(headerPath);
 
      // Map each struct/type/enum name to the include directive
      for (const sym of symbols) {
        if (
          sym.kind === ESymbolKind.Struct ||
          sym.kind === ESymbolKind.Type ||
          sym.kind === ESymbolKind.Enum ||
          sym.kind === ESymbolKind.Class
        ) {
          // Only add if we don't already have a mapping (first include wins)
          if (!typeHeaders.has(sym.name)) {
            typeHeaders.set(sym.name, directive);
          }
        }
      }
    }
 
    return typeHeaders;
  }
}
 
export default ExternalTypeHeaderBuilder;