/ src / utils / diff.ts
diff.ts
 1  import { type Hunk, structuredPatch } from 'diff'
 2  
 3  const CONTEXT_LINES = 3
 4  
 5  // For some reason, & confuses the diff library, so we replace it with a token,
 6  // then substitute it back in after the diff is computed.
 7  const AMPERSAND_TOKEN = '<<:AMPERSAND_TOKEN:>>'
 8  
 9  const DOLLAR_TOKEN = '<<:DOLLAR_TOKEN:>>'
10  
11  export function getPatch({
12    filePath,
13    fileContents,
14    oldStr,
15    newStr,
16  }: {
17    filePath: string
18    fileContents: string
19    oldStr: string
20    newStr: string
21  }): Hunk[] {
22    return structuredPatch(
23      filePath,
24      filePath,
25      fileContents.replaceAll('&', AMPERSAND_TOKEN).replaceAll('$', DOLLAR_TOKEN),
26      fileContents
27        .replaceAll('&', AMPERSAND_TOKEN)
28        .replaceAll('$', DOLLAR_TOKEN)
29        .replace(
30          oldStr.replaceAll('&', AMPERSAND_TOKEN).replaceAll('$', DOLLAR_TOKEN),
31          newStr.replaceAll('&', AMPERSAND_TOKEN).replaceAll('$', DOLLAR_TOKEN),
32        ),
33      undefined,
34      undefined,
35      { context: CONTEXT_LINES },
36    ).hunks.map(_ => ({
37      ..._,
38      lines: _.lines.map(_ =>
39        _.replaceAll(AMPERSAND_TOKEN, '&').replaceAll(DOLLAR_TOKEN, '$'),
40      ),
41    }))
42  }