All files / src/find-duplicate-segments findDuplicateSegments.ts

0% Statements 0/29
0% Branches 0/5
0% Functions 0/5
0% Lines 0/28

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                                                                                                                                                         
import * as crypto from "crypto";
 
import type { HistoryEntry, SegmentKey } from "@featurevisor/types";
 
import { Dependencies } from "../dependencies";
 
export interface DuplicateSegmentsOptions {
  authors?: boolean;
}
 
export interface DuplicateSegmentsResult {
  segments: SegmentKey[];
  authors?: string[];
}
 
export async function findDuplicateSegments(
  deps: Dependencies,
  options: DuplicateSegmentsOptions = {},
): Promise<DuplicateSegmentsResult[]> {
  const { datasource } = deps;
 
  const segments = await datasource.listSegments();
 
  const segmentsWithHash: { segmentKey: SegmentKey; hash: string }[] = [];
  for (const segmentKey of segments) {
    const segment = await datasource.readSegment(segmentKey);
    const conditions = JSON.stringify(segment.conditions);
    const hash = crypto.createHash("sha256").update(conditions).digest("hex");
 
    segmentsWithHash.push({
      segmentKey,
      hash,
    });
  }
 
  const groupedSegments: { [hash: string]: SegmentKey[] } = segmentsWithHash.reduce(
    (acc, { segmentKey, hash }) => {
      if (!acc[hash]) {
        acc[hash] = [];
      }
      acc[hash].push(segmentKey);
      return acc;
    },
    {},
  );
 
  const duplicateSegments = Object.values(groupedSegments).filter(
    (segmentKeys) => segmentKeys.length > 1,
  );
  const result: DuplicateSegmentsResult[] = [];
 
  for (const segmentKeys of duplicateSegments) {
    const entry: DuplicateSegmentsResult = {
      segments: segmentKeys,
    };
 
    if (options.authors) {
      const historyEntries: HistoryEntry[] = [];
 
      for (const segmentKey of segmentKeys) {
        const entries = await datasource.listHistoryEntries("segment", segmentKey);
 
        entries.forEach((entry) => {
          historyEntries.push(entry);
        });
      }
 
      const authors = Array.from(new Set(historyEntries.map((entry) => entry.author)));
      entry.authors = authors;
    }
 
    result.push(entry);
  }
 
  return result;
}