Skip to content

Commit 1bdac30

Browse files
committed
Add validation for patch block integrity and enhance error handling in search-replace parsing
1 parent df1cc8c commit 1bdac30

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

src/patch_file_mcp/server.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,45 @@ def main():
8080
# Tools
8181
#
8282

83+
def validate_block_integrity(patch_content):
84+
"""
85+
Validate the integrity of patch blocks before parsing.
86+
Checks for balanced markers and correct sequence.
87+
"""
88+
# Check marker balance
89+
search_count = patch_content.count("<<<<<<< SEARCH")
90+
separator_count = patch_content.count("=======")
91+
replace_count = patch_content.count(">>>>>>> REPLACE")
92+
93+
if not (search_count == separator_count == replace_count):
94+
raise ValueError(
95+
f"Malformed patch format: Unbalanced markers - "
96+
f"{search_count} SEARCH, {separator_count} separator, {replace_count} REPLACE markers"
97+
)
98+
99+
# Check marker sequence
100+
markers = []
101+
for line in patch_content.splitlines():
102+
line = line.strip()
103+
if line in ["<<<<<<< SEARCH", "=======", ">>>>>>> REPLACE"]:
104+
markers.append(line)
105+
106+
# Verify correct marker sequence (always SEARCH, SEPARATOR, REPLACE pattern)
107+
for i in range(0, len(markers), 3):
108+
if i+2 < len(markers):
109+
if markers[i] != "<<<<<<< SEARCH" or markers[i+1] != "=======" or markers[i+2] != ">>>>>>> REPLACE":
110+
raise ValueError(
111+
f"Malformed patch format: Incorrect marker sequence at position {i}: "
112+
f"Expected [SEARCH, SEPARATOR, REPLACE], got {markers[i:i+3]}"
113+
)
114+
115+
# Check for nested markers in each block
116+
sections = patch_content.split("<<<<<<< SEARCH")
117+
for i, section in enumerate(sections[1:], 1): # Skip first empty section
118+
if "<<<<<<< SEARCH" in section and section.find(">>>>>>> REPLACE") > section.find("<<<<<<< SEARCH"):
119+
raise ValueError(f"Malformed patch format: Nested SEARCH marker in block {i}")
120+
121+
83122
def parse_search_replace_blocks(patch_content):
84123
"""
85124
Parse multiple search-replace blocks from the patch content.
@@ -89,6 +128,9 @@ def parse_search_replace_blocks(patch_content):
89128
search_marker = "<<<<<<< SEARCH"
90129
separator = "======="
91130
replace_marker = ">>>>>>> REPLACE"
131+
132+
# First validate patch integrity
133+
validate_block_integrity(patch_content)
92134

93135
# Use regex to extract all blocks
94136
pattern = f"{search_marker}\\n(.*?)\\n{separator}\\n(.*?)\\n{replace_marker}"
@@ -125,6 +167,13 @@ def parse_search_replace_blocks(patch_content):
125167

126168
search_text = "\n".join(lines[search_start:separator_idx])
127169
replace_text = "\n".join(lines[separator_idx + 1:replace_end])
170+
171+
# Check for markers in the search or replace text
172+
if any(marker in search_text for marker in [search_marker, separator, replace_marker]):
173+
raise ValueError(f"Block {len(blocks)+1}: Search text contains patch markers")
174+
if any(marker in replace_text for marker in [search_marker, separator, replace_marker]):
175+
raise ValueError(f"Block {len(blocks)+1}: Replace text contains patch markers")
176+
128177
blocks.append((search_text, replace_text))
129178

130179
i = replace_end + 1
@@ -136,6 +185,13 @@ def parse_search_replace_blocks(patch_content):
136185
else:
137186
raise ValueError("Invalid patch format. Expected block format with SEARCH/REPLACE markers.")
138187

188+
# Check for markers in matched content
189+
for i, (search_text, replace_text) in enumerate(matches):
190+
if any(marker in search_text for marker in [search_marker, separator, replace_marker]):
191+
raise ValueError(f"Block {i+1}: Search text contains patch markers")
192+
if any(marker in replace_text for marker in [search_marker, separator, replace_marker]):
193+
raise ValueError(f"Block {i+1}: Replace text contains patch markers")
194+
139195
return matches
140196

141197

0 commit comments

Comments
 (0)