All files / utils RequirementAggregator.ts

100% Statements 16/16
90% Branches 9/10
100% Functions 4/4
100% Lines 14/14

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                                309x   309x 309x 329x 329x 312x 312x   17x 2x         312x                   312x 5x 5x 3x            
import type IFileResult from "../transpiler/types/IFileResult";
import type IRecordedRequirement from "../transpiler/types/IRecordedRequirement";
import type IRequirementSite from "../transpiler/types/IRequirementSite";
import type TRequirementKey from "../transpiler/types/TRequirementKey";
import RequirementSites from "./RequirementSites";
 
/**
 * Issue #1143: Fold per-file toolchain requirements into a project-level view.
 *
 * A static matrix can only say what C-Next *might* need. Merging what each file
 * actually recorded is what lets the transpiler answer the question a user
 * choosing a toolchain is really asking: what does *this* project need?
 */
class RequirementAggregator {
  /** Union file requirements by key, concatenating their source sites. */
  static merge(files: readonly IFileResult[]): readonly IRecordedRequirement[] {
    const merged = new Map<TRequirementKey, IRequirementSite[]>();
 
    for (const file of files) {
      for (const entry of file.requirements ?? []) {
        const sites = merged.get(entry.key);
        if (sites === undefined) {
          merged.set(entry.key, [...entry.sites]);
          continue;
        }
        for (const site of entry.sites) {
          RequirementSites.addUnique(sites, site);
        }
      }
    }
 
    return Array.from(merged.entries()).map(([key, sites]) => ({
      key,
      sites: RequirementAggregator.sortSites(sites),
    }));
  }
 
  /** Stable site ordering, so reports and snapshots do not churn. */
  private static sortSites(
    sites: readonly IRequirementSite[],
  ): readonly IRequirementSite[] {
    return sites.slice().sort((left, right) => {
      const byPath = left.sourcePath.localeCompare(right.sourcePath);
      if (byPath !== 0) return byPath;
      return (left.line ?? 0) - (right.line ?? 0);
    });
  }
}
 
export default RequirementAggregator;