@@ -80,6 +80,45 @@ def main():
80
80
# Tools
81
81
#
82
82
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
+
83
122
def parse_search_replace_blocks (patch_content ):
84
123
"""
85
124
Parse multiple search-replace blocks from the patch content.
@@ -89,6 +128,9 @@ def parse_search_replace_blocks(patch_content):
89
128
search_marker = "<<<<<<< SEARCH"
90
129
separator = "======="
91
130
replace_marker = ">>>>>>> REPLACE"
131
+
132
+ # First validate patch integrity
133
+ validate_block_integrity (patch_content )
92
134
93
135
# Use regex to extract all blocks
94
136
pattern = f"{ search_marker } \\ n(.*?)\\ n{ separator } \\ n(.*?)\\ n{ replace_marker } "
@@ -125,6 +167,13 @@ def parse_search_replace_blocks(patch_content):
125
167
126
168
search_text = "\n " .join (lines [search_start :separator_idx ])
127
169
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
+
128
177
blocks .append ((search_text , replace_text ))
129
178
130
179
i = replace_end + 1
@@ -136,6 +185,13 @@ def parse_search_replace_blocks(patch_content):
136
185
else :
137
186
raise ValueError ("Invalid patch format. Expected block format with SEARCH/REPLACE markers." )
138
187
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
+
139
195
return matches
140
196
141
197
0 commit comments