← Back
mainapp/services/DiffEngine.php
<?php

class DiffEngine
{
  private BlobStore $blobs;
  public function __construct(BlobStore $blobs) { $this->blobs = $blobs; }

  public function diffSnapshots(array $a, array $b): array
  {
    $paths = array_unique(array_merge(array_keys($a), array_keys($b)));
    sort($paths);

    $changes = [];
    foreach ($paths as $p) {
      $inA = array_key_exists($p, $a);
      $inB = array_key_exists($p, $b);

      if (!$inA && $inB) $changes[] = ['path'=>$p,'type'=>'added','a'=>null,'b'=>$b[$p]];
      elseif ($inA && !$inB) $changes[] = ['path'=>$p,'type'=>'deleted','a'=>$a[$p],'b'=>null];
      elseif ($inA && $inB && $a[$p] !== $b[$p]) $changes[] = ['path'=>$p,'type'=>'modified','a'=>$a[$p],'b'=>$b[$p]];
    }
    return $changes;
  }

  public function lineDiff(string $old, string $new): array
  {
    $a = preg_split("/\r\n|\n|\r/", $old);
    $b = preg_split("/\r\n|\n|\r/", $new);

    $n = count($a); $m = count($b);
    $dp = array_fill(0, $n+1, array_fill(0, $m+1, 0));

    for ($i=$n-1; $i>=0; $i--) {
      for ($j=$m-1; $j>=0; $j--) {
        $dp[$i][$j] = ($a[$i] === $b[$j]) ? $dp[$i+1][$j+1] + 1 : max($dp[$i+1][$j], $dp[$i][$j+1]);
      }
    }

    $i=0; $j=0; $out=[];
    while ($i<$n && $j<$m) {
      if ($a[$i] === $b[$j]) {
        $out[] = ['type'=>'ctx','line'=>$a[$i]];
        $i++; $j++;
      } elseif ($dp[$i+1][$j] >= $dp[$i][$j+1]) {
        $out[] = ['type'=>'del','line'=>$a[$i]];
        $i++;
      } else {
        $out[] = ['type'=>'add','line'=>$b[$j]];
        $j++;
      }
    }
    while ($i<$n) { $out[]=['type'=>'del','line'=>$a[$i++]]; }
    while ($j<$m) { $out[]=['type'=>'add','line'=>$b[$j++]]; }
    return $out;
  }

  public function renderLineDiffHtml(array $diffLines): string
  {
    $h = '<pre class="diff mono" style="white-space:pre;overflow:auto;border:1px solid #e5e7eb;border-radius:10px;padding:10px;background:#0d1117;color:#c9d1d9;">';
    foreach ($diffLines as $d) {
      $line = htmlspecialchars($d['line'] ?? '', ENT_QUOTES, 'UTF-8');
      if ($d['type'] === 'add') $h .= "<div style='color:#3fb950;'>+ {$line}</div>";
      elseif ($d['type'] === 'del') $h .= "<div style='color:#ff7b72;'>- {$line}</div>";
      else $h .= "<div style='color:#c9d1d9;'>  {$line}</div>";
    }
    $h .= '</pre>';
    return $h;
  }
}