chore: consolidate patch prefix constants in apply‑patch.ts (#274)

This PR replaces all hard‑coded patch markers in apply‑patch.ts with the
corresponding constants (now) exported from parse‑apply‑patch.ts.

Changes
• Import PATCH_PREFIX, PATCH_SUFFIX, ADD_FILE_PREFIX,
DELETE_FILE_PREFIX, UPDATE_FILE_PREFIX, MOVE_FILE_TO_PREFIX,
END_OF_FILE_PREFIX, and HUNK_ADD_LINE_PREFIX from parse‑apply‑patch.ts.
	•	Remove duplicate string literals for patch markers in apply‑patch.ts.
• Changed is_done() to trim the input to account for the slight
difference between the variables.

Why
• DRY & Consistency: Ensures a single source of truth for patch
prefixes.
• Maintainability: Simplifies future updates to prefix values by
centralizing them.
	•	Readability: Makes the code more declarative and self‑documenting.

All tests are passing, lint and format was ran.
This commit is contained in:
Michael
2025-04-18 02:00:30 +02:00
committed by GitHub
parent ec21e19308
commit f4b9153f78
2 changed files with 55 additions and 42 deletions

View File

@@ -22,13 +22,14 @@ export type ApplyPatchOp =
| ApplyPatchDeleteFileOp | ApplyPatchDeleteFileOp
| ApplyPatchUpdateFileOp; | ApplyPatchUpdateFileOp;
const PATCH_PREFIX = "*** Begin Patch\n"; export const PATCH_PREFIX = "*** Begin Patch\n";
const PATCH_SUFFIX = "\n*** End Patch"; export const PATCH_SUFFIX = "\n*** End Patch";
const ADD_FILE_PREFIX = "*** Add File: "; export const ADD_FILE_PREFIX = "*** Add File: ";
const DELETE_FILE_PREFIX = "*** Delete File: "; export const DELETE_FILE_PREFIX = "*** Delete File: ";
const UPDATE_FILE_PREFIX = "*** Update File: "; export const UPDATE_FILE_PREFIX = "*** Update File: ";
const END_OF_FILE_PREFIX = "*** End of File"; export const MOVE_FILE_TO_PREFIX = "*** Move to: ";
const HUNK_ADD_LINE_PREFIX = "+"; export const END_OF_FILE_PREFIX = "*** End of File";
export const HUNK_ADD_LINE_PREFIX = "+";
/** /**
* @returns null when the patch is invalid * @returns null when the patch is invalid

View File

@@ -3,6 +3,16 @@
import fs from "fs"; import fs from "fs";
import path from "path"; import path from "path";
import {
ADD_FILE_PREFIX,
DELETE_FILE_PREFIX,
END_OF_FILE_PREFIX,
MOVE_FILE_TO_PREFIX,
PATCH_SUFFIX,
UPDATE_FILE_PREFIX,
HUNK_ADD_LINE_PREFIX,
PATCH_PREFIX,
} from "src/parse-apply-patch";
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Types & Models // Types & Models
@@ -103,7 +113,7 @@ class Parser {
} }
if ( if (
prefixes && prefixes &&
prefixes.some((p) => this.lines[this.index]!.startsWith(p)) prefixes.some((p) => this.lines[this.index]!.startsWith(p.trim()))
) { ) {
return true; return true;
} }
@@ -130,13 +140,13 @@ class Parser {
} }
parse(): void { parse(): void {
while (!this.is_done(["*** End Patch"])) { while (!this.is_done([PATCH_SUFFIX])) {
let path = this.read_str("*** Update File: "); let path = this.read_str(UPDATE_FILE_PREFIX);
if (path) { if (path) {
if (this.patch.actions[path]) { if (this.patch.actions[path]) {
throw new DiffError(`Update File Error: Duplicate Path: ${path}`); throw new DiffError(`Update File Error: Duplicate Path: ${path}`);
} }
const moveTo = this.read_str("*** Move to: "); const moveTo = this.read_str(MOVE_FILE_TO_PREFIX);
if (!(path in this.current_files)) { if (!(path in this.current_files)) {
throw new DiffError(`Update File Error: Missing File: ${path}`); throw new DiffError(`Update File Error: Missing File: ${path}`);
} }
@@ -146,7 +156,7 @@ class Parser {
this.patch.actions[path] = action; this.patch.actions[path] = action;
continue; continue;
} }
path = this.read_str("*** Delete File: "); path = this.read_str(DELETE_FILE_PREFIX);
if (path) { if (path) {
if (this.patch.actions[path]) { if (this.patch.actions[path]) {
throw new DiffError(`Delete File Error: Duplicate Path: ${path}`); throw new DiffError(`Delete File Error: Duplicate Path: ${path}`);
@@ -157,7 +167,7 @@ class Parser {
this.patch.actions[path] = { type: ActionType.DELETE, chunks: [] }; this.patch.actions[path] = { type: ActionType.DELETE, chunks: [] };
continue; continue;
} }
path = this.read_str("*** Add File: "); path = this.read_str(ADD_FILE_PREFIX);
if (path) { if (path) {
if (this.patch.actions[path]) { if (this.patch.actions[path]) {
throw new DiffError(`Add File Error: Duplicate Path: ${path}`); throw new DiffError(`Add File Error: Duplicate Path: ${path}`);
@@ -170,7 +180,7 @@ class Parser {
} }
throw new DiffError(`Unknown Line: ${this.lines[this.index]}`); throw new DiffError(`Unknown Line: ${this.lines[this.index]}`);
} }
if (!this.startswith("*** End Patch")) { if (!this.startswith(PATCH_SUFFIX.trim())) {
throw new DiffError("Missing End Patch"); throw new DiffError("Missing End Patch");
} }
this.index += 1; this.index += 1;
@@ -183,11 +193,11 @@ class Parser {
while ( while (
!this.is_done([ !this.is_done([
"*** End Patch", PATCH_SUFFIX,
"*** Update File:", UPDATE_FILE_PREFIX,
"*** Delete File:", DELETE_FILE_PREFIX,
"*** Add File:", ADD_FILE_PREFIX,
"*** End of File", END_OF_FILE_PREFIX,
]) ])
) { ) {
const defStr = this.read_str("@@ "); const defStr = this.read_str("@@ ");
@@ -258,14 +268,14 @@ class Parser {
const lines: Array<string> = []; const lines: Array<string> = [];
while ( while (
!this.is_done([ !this.is_done([
"*** End Patch", PATCH_SUFFIX,
"*** Update File:", UPDATE_FILE_PREFIX,
"*** Delete File:", DELETE_FILE_PREFIX,
"*** Add File:", ADD_FILE_PREFIX,
]) ])
) { ) {
const s = this.read_str(); const s = this.read_str();
if (!s.startsWith("+")) { if (!s.startsWith(HUNK_ADD_LINE_PREFIX)) {
throw new DiffError(`Invalid Add File Line: ${s}`); throw new DiffError(`Invalid Add File Line: ${s}`);
} }
lines.push(s.slice(1)); lines.push(s.slice(1));
@@ -349,12 +359,14 @@ function peek_next_section(
while (index < lines.length) { while (index < lines.length) {
const s = lines[index]!; const s = lines[index]!;
if ( if (
s.startsWith("@@") || [
s.startsWith("*** End Patch") || "@@",
s.startsWith("*** Update File:") || PATCH_SUFFIX,
s.startsWith("*** Delete File:") || UPDATE_FILE_PREFIX,
s.startsWith("*** Add File:") || DELETE_FILE_PREFIX,
s.startsWith("*** End of File") ADD_FILE_PREFIX,
END_OF_FILE_PREFIX,
].some((p) => s.startsWith(p.trim()))
) { ) {
break; break;
} }
@@ -367,7 +379,7 @@ function peek_next_section(
index += 1; index += 1;
const lastMode: "keep" | "add" | "delete" = mode; const lastMode: "keep" | "add" | "delete" = mode;
let line = s; let line = s;
if (line[0] === "+") { if (line[0] === HUNK_ADD_LINE_PREFIX) {
mode = "add"; mode = "add";
} else if (line[0] === "-") { } else if (line[0] === "-") {
mode = "delete"; mode = "delete";
@@ -412,7 +424,7 @@ function peek_next_section(
ins_lines: insLines, ins_lines: insLines,
}); });
} }
if (index < lines.length && lines[index] === "*** End of File") { if (index < lines.length && lines[index] === END_OF_FILE_PREFIX) {
index += 1; index += 1;
return [old, chunks, index, true]; return [old, chunks, index, true];
} }
@@ -430,8 +442,8 @@ export function text_to_patch(
const lines = text.trim().split("\n"); const lines = text.trim().split("\n");
if ( if (
lines.length < 2 || lines.length < 2 ||
!(lines[0] ?? "").startsWith("*** Begin Patch") || !(lines[0] ?? "").startsWith(PATCH_PREFIX.trim()) ||
lines[lines.length - 1] !== "*** End Patch" lines[lines.length - 1] !== PATCH_SUFFIX.trim()
) { ) {
throw new DiffError("Invalid patch text"); throw new DiffError("Invalid patch text");
} }
@@ -445,11 +457,11 @@ export function identify_files_needed(text: string): Array<string> {
const lines = text.trim().split("\n"); const lines = text.trim().split("\n");
const result = new Set<string>(); const result = new Set<string>();
for (const line of lines) { for (const line of lines) {
if (line.startsWith("*** Update File: ")) { if (line.startsWith(UPDATE_FILE_PREFIX)) {
result.add(line.slice("*** Update File: ".length)); result.add(line.slice(UPDATE_FILE_PREFIX.length));
} }
if (line.startsWith("*** Delete File: ")) { if (line.startsWith(DELETE_FILE_PREFIX)) {
result.add(line.slice("*** Delete File: ".length)); result.add(line.slice(DELETE_FILE_PREFIX.length));
} }
} }
return [...result]; return [...result];
@@ -459,8 +471,8 @@ export function identify_files_added(text: string): Array<string> {
const lines = text.trim().split("\n"); const lines = text.trim().split("\n");
const result = new Set<string>(); const result = new Set<string>();
for (const line of lines) { for (const line of lines) {
if (line.startsWith("*** Add File: ")) { if (line.startsWith(ADD_FILE_PREFIX)) {
result.add(line.slice("*** Add File: ".length)); result.add(line.slice(ADD_FILE_PREFIX.length));
} }
} }
return [...result]; return [...result];
@@ -581,8 +593,8 @@ export function process_patch(
writeFn: (p: string, c: string) => void, writeFn: (p: string, c: string) => void,
removeFn: (p: string) => void, removeFn: (p: string) => void,
): string { ): string {
if (!text.startsWith("*** Begin Patch")) { if (!text.startsWith(PATCH_PREFIX)) {
throw new DiffError("Patch must start with *** Begin Patch"); throw new DiffError("Patch must start with *** Begin Patch\\n");
} }
const paths = identify_files_needed(text); const paths = identify_files_needed(text);
const orig = load_files(paths, openFn); const orig = load_files(paths, openFn);