From a414ef1cd556805ee834fc0ee7e90276f22a3aa0 Mon Sep 17 00:00:00 2001 From: Mradul Singh Date: Thu, 12 Nov 2026 12:10:20 +0530 Subject: [PATCH] parser: only drop "\ No newline" marker lines The parser removed every "\ No newline at end of file" string from the whole input before splitting it into lines. When the diff is for a patch file, content lines like " \ No newline at end of file" lost that text and showed up as " ", "-" or "+". Now only lines that start with "\ " are skipped. This matches how git apply finds the marker, and it also skips translated markers from GNU diff. Fixes #598 --- src/__tests__/diff-parser-tests.ts | 80 ++++++++++++++++++++++++++++++ src/diff-parser.ts | 9 ++-- 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/src/__tests__/diff-parser-tests.ts b/src/__tests__/diff-parser-tests.ts index dde2778e..880be683 100644 --- a/src/__tests__/diff-parser-tests.ts +++ b/src/__tests__/diff-parser-tests.ts @@ -2514,5 +2514,85 @@ describe('DiffParser', () => { ] `); }); + + it('should keep "\\ No newline at end of file" text inside content lines', () => { + const diff = + 'diff --git a/fix.patch b/fix.patch\n' + + 'index 0000001..0ddf2ba 100644\n' + + '--- a/fix.patch\n' + + '+++ b/fix.patch\n' + + '@@ -1,4 +1,4 @@\n' + + ' @@ -1 +1 @@\n' + + '-+old\n' + + '-\\ No newline at end of file\n' + + '++new\n' + + '+\\ No newline at end of file\n' + + ' \\ No newline at end of file\n' + + '\\ No newline at end of file\n'; + + const result = parse(diff); + expect(result).toMatchInlineSnapshot(` + [ + { + "addedLines": 2, + "blocks": [ + { + "header": "@@ -1,4 +1,4 @@", + "lines": [ + { + "content": " @@ -1 +1 @@", + "newNumber": 1, + "oldNumber": 1, + "type": "context", + }, + { + "content": "-+old", + "newNumber": undefined, + "oldNumber": 2, + "type": "delete", + }, + { + "content": "-\\ No newline at end of file", + "newNumber": undefined, + "oldNumber": 3, + "type": "delete", + }, + { + "content": "++new", + "newNumber": 2, + "oldNumber": undefined, + "type": "insert", + }, + { + "content": "+\\ No newline at end of file", + "newNumber": 3, + "oldNumber": undefined, + "type": "insert", + }, + { + "content": " \\ No newline at end of file", + "newNumber": 4, + "oldNumber": 4, + "type": "context", + }, + ], + "newStartLine": 1, + "oldStartLine": 1, + "oldStartLine2": null, + }, + ], + "checksumAfter": "0ddf2ba", + "checksumBefore": "0000001", + "deletedLines": 2, + "isCombined": false, + "isGitDiff": true, + "language": "patch", + "mode": "100644", + "newName": "fix.patch", + "oldName": "fix.patch", + }, + ] + `); + }); }); }); diff --git a/src/diff-parser.ts b/src/diff-parser.ts index 83d9c630..f3bf95f8 100644 --- a/src/diff-parser.ts +++ b/src/diff-parser.ts @@ -93,10 +93,7 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil const combinedNewFile = /^new file mode (\d{6})/; const combinedDeletedFile = /^deleted file mode (\d{6}),(\d{6})/; - const diffLines = diffInput - .replace(/\\ No newline at end of file/g, '') - .replace(/\r\n?/g, '\n') - .split('\n'); + const diffLines = diffInput.replace(/\r\n?/g, '\n').split('\n'); /* Add previous block(if exists) before start a new file */ function saveBlock(): void { @@ -261,7 +258,9 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil // Unmerged paths, and possibly other non-diffable files // https://github.com/scottgonzalez/pretty-diff/issues/11 // Also, remove some useless lines - if (!line || line.startsWith('*')) { + // Lines starting with "\ " are markers like "\ No newline at end of file" + // (the message text can be translated, so only the prefix is checked) + if (!line || line.startsWith('*') || line.startsWith('\\ ')) { return; }