All files / src/lib/compiler buildModuleUsage.ts

100% Statements 30/30
81.25% Branches 13/16
100% Functions 4/4
100% Lines 27/27

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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 972x 2x   2x                         8x   2x       8x 8x 15x 15x 15x     8x     2x             4x 4x 8x 8x 6x                 2x             1x   1x             3x     2x         3x           3x 3x   1x           2x          
import fs from "fs-extra";
import Path from "path";
import type { BuildManifest, BuildSourceOrigin } from "./buildManifest";
import {
  classifyAreaName,
  parseObjectAreaSizes,
  type MemoryRegion,
  type RegionUsage,
} from "./buildArtifactParsers";
 
export type BuildModuleUsage = {
  sourceFile: string;
  usage: RegionUsage;
  origin: BuildSourceOrigin;
};
 
const emptyUsage = (): RegionUsage => ({ bank0: 0, wram: 0, bankedRom: 0 });
 
const usageForAreaSizes = (
  sizes: Record<string, number>,
  regionForArea: (name: string) => MemoryRegion,
): RegionUsage => {
  const usage = emptyUsage();
  for (const [area, size] of Object.entries(sizes)) {
    const region = regionForArea(area);
    Eif (region === "bank0" || region === "wram" || region === "bankedRom") {
      usage[region] += size;
    }
  }
  return usage;
};
 
export const analyseBuildObjects = async ({
  manifest,
  allowMissing,
}: {
  manifest: BuildManifest;
  allowMissing: boolean;
}): Promise<BuildModuleUsage[]> => {
  const modules: BuildModuleUsage[] = [];
  for (const source of manifest.sources) {
    try {
      const objectSource = await fs.readFile(source.objectPath, "utf8");
      modules.push({
        sourceFile: source.sourcePath,
        usage: usageForAreaSizes(
          parseObjectAreaSizes(objectSource),
          classifyAreaName,
        ),
        origin: source.origin,
      });
    } catch (error) {
      if (
        allowMissing &&
        error &&
        typeof error === "object" &&
        "code" in error &&
        error.code === "ENOENT"
      ) {
        continue;
      }
      throw new Error(
        `Unable to read build artifact "${source.objectPath}" for source "${source.sourcePath}": ${
          error instanceof Error ? error.message : String(error)
        }`,
      );
    }
  }
  return modules;
};
 
export const analyseMusicDriverUsage = async ({
  manifest,
}: {
  manifest: BuildManifest;
}): Promise<RegionUsage> => {
  const musicDriverPath = Path.join(
    manifest.buildRoot,
    "lib",
    "hUGEDriver.lib",
  );
  let musicDriverSource: string;
  try {
    musicDriverSource = await fs.readFile(musicDriverPath, "utf8");
  } catch (error) {
    throw new Error(
      `Unable to read build artifact "${musicDriverPath}": ${
        error instanceof Error ? error.message : String(error)
      }`,
    );
  }
  return usageForAreaSizes(
    parseObjectAreaSizes(musicDriverSource),
    classifyAreaName,
  );
};