( oldPath: string, newPath: string, oldContent: string | null, newContent: string | null, )
| 410 | } |
| 411 | |
| 412 | function unifiedFilePatch( |
| 413 | oldPath: string, |
| 414 | newPath: string, |
| 415 | oldContent: string | null, |
| 416 | newContent: string | null, |
| 417 | ): string { |
| 418 | const oldLines = fileLines(oldContent ?? ""); |
| 419 | const newLines = fileLines(newContent ?? ""); |
| 420 | let prefix = 0; |
| 421 | while ( |
| 422 | prefix < oldLines.length && |
| 423 | prefix < newLines.length && |
| 424 | oldLines[prefix] === newLines[prefix] |
| 425 | ) { |
| 426 | prefix += 1; |
| 427 | } |
| 428 | |
| 429 | let suffix = 0; |
| 430 | while ( |
| 431 | suffix < oldLines.length - prefix && |
| 432 | suffix < newLines.length - prefix && |
| 433 | oldLines[oldLines.length - 1 - suffix] === newLines[newLines.length - 1 - suffix] |
| 434 | ) { |
| 435 | suffix += 1; |
| 436 | } |
| 437 | |
| 438 | const contextBefore = Math.min(3, prefix); |
| 439 | const contextAfter = Math.min(3, suffix); |
| 440 | const oldChanged = oldLines.slice(prefix, oldLines.length - suffix); |
| 441 | const newChanged = newLines.slice(prefix, newLines.length - suffix); |
| 442 | const before = oldLines.slice(prefix - contextBefore, prefix); |
| 443 | const after = oldLines.slice(oldLines.length - suffix, oldLines.length - suffix + contextAfter); |
| 444 | const oldCount = contextBefore + oldChanged.length + contextAfter; |
| 445 | const newCount = contextBefore + newChanged.length + contextAfter; |
| 446 | const oldStart = oldContent === null ? 0 : prefix - contextBefore + 1; |
| 447 | const newStart = newContent === null ? 0 : prefix - contextBefore + 1; |
| 448 | const displayOld = oldContent === null ? "/dev/null" : `a/${oldPath}`; |
| 449 | const displayNew = newContent === null ? "/dev/null" : `b/${newPath}`; |
| 450 | |
| 451 | return [ |
| 452 | `diff --git a/${oldPath} b/${newPath}`, |
| 453 | oldContent === null ? "new file mode 100644" : undefined, |
| 454 | newContent === null ? "deleted file mode 100644" : undefined, |
| 455 | `--- ${displayOld}`, |
| 456 | `+++ ${displayNew}`, |
| 457 | `@@ -${hunkRange(oldStart, oldCount)} +${hunkRange(newStart, newCount)} @@`, |
| 458 | ...before.map((line) => ` ${line}`), |
| 459 | ...oldChanged.map((line) => `-${line}`), |
| 460 | ...newChanged.map((line) => `+${line}`), |
| 461 | ...after.map((line) => ` ${line}`), |
| 462 | ] |
| 463 | .filter((line): line is string => line !== undefined) |
| 464 | .join("\n"); |
| 465 | } |
| 466 | |
| 467 | function countPatchStats(patch: string): { additions: number; removals: number } { |
| 468 | let additions = 0; |
no test coverage detected