51 lines · 1.8 KB
import { diffArrays } from "diff";
import type { BlameRange } from "~/lib/code-intel";

const MAX_EDIT_LENGTH = 20_000;
const DIFF_TIMEOUT_MS = 1000;

/** Maps each new-version line index to its old-version index (-1 when added); null if the diff gave up. */
export function mapLines(oldLines: string[], newLines: string[]): Int32Array | null {
  const changes = diffArrays(oldLines, newLines, { maxEditLength: MAX_EDIT_LENGTH, timeout: DIFF_TIMEOUT_MS });
  if (!changes) return null;
  const map = new Int32Array(newLines.length).fill(-1);
  let oldIndex = 0;
  let newIndex = 0;
  for (const change of changes) {
    const count = change.count;
    if (change.added) newIndex += count;
    else if (change.removed) oldIndex += count;
    else {
      for (let offset = 0; offset < count; offset++) map[newIndex + offset] = oldIndex + offset;
      oldIndex += count;
      newIndex += count;
    }
  }
  return map;
}

export function splitLines(text: string): string[] {
  const lines = text.split("\n");
  if (lines.length > 1 && lines[lines.length - 1] === "") lines.pop();
  return lines;
}

export function compressRanges(owners: Array<string | null>, fallback: string): BlameRange[] {
  const ranges: BlameRange[] = [];
  for (let line = 0; line < owners.length; line++) {
    const sha = owners[line] ?? fallback;
    const last = ranges[ranges.length - 1];
    if (last && last.sha === sha) last.count++;
    else ranges.push({ start: line, count: 1, sha });
  }