diff --git a/packages/core/src/patch.ts b/packages/core/src/patch.ts index 7969ae01afb..a297761fe0e 100644 --- a/packages/core/src/patch.ts +++ b/packages/core/src/patch.ts @@ -44,7 +44,9 @@ export interface FileUpdate { } export function parse(patchText: string): Result.Result, ParseError> { - const lines = stripHeredoc(patchText.trim()).split("\n") + const lines = stripHeredoc(patchText.trim()) + .split("\n") + .map((line) => (line.endsWith("\r") ? line.slice(0, -1) : line)) const begin = lines.findIndex((line) => line.trim() === "*** Begin Patch") const end = lines.findIndex((line) => line.trim() === "*** End Patch") if (begin === -1) return Result.fail(new BoundaryError({ boundary: "first" })) diff --git a/packages/core/test/patch.test.ts b/packages/core/test/patch.test.ts index 2d872c7f310..9646452f17f 100644 --- a/packages/core/test/patch.test.ts +++ b/packages/core/test/patch.test.ts @@ -91,6 +91,28 @@ describe("Patch", () => { ]) }) + test("strips one carriage return from CRLF patch lines", () => { + expect(parse("*** Begin Patch\r\n*** Update File: file.txt\r\n@@\r\n-old\r\n+new\r\n*** End Patch\r\n")).toEqual([ + { + type: "update", + path: "file.txt", + movePath: undefined, + chunks: [{ oldLines: ["old"], newLines: ["new"], changeContext: undefined, endOfFile: undefined }], + }, + ]) + }) + + test("preserves an extra carriage return in CRLF patch lines", () => { + expect(parse("*** Begin Patch\r\n*** Update File: file.txt\r\n@@\r\n-old\r\r\n+new\r\n*** End Patch\r\n")).toEqual([ + { + type: "update", + path: "file.txt", + movePath: undefined, + chunks: [{ oldLines: ["old\r"], newLines: ["new"], changeContext: undefined, endOfFile: undefined }], + }, + ]) + }) + test("derives fuzzy line updates while preserving BOM", () => { const update = Patch.derive("update.txt", [{ oldLines: [" old "], newLines: ["new"] }], "\uFEFFold\n") expect(update).toEqual({ content: "new\n", bom: true })