(path: string, content: string, hunks: UpdateHunk[])
| 247 | } |
| 248 | |
| 249 | function applyHunks(path: string, content: string, hunks: UpdateHunk[]): string { |
| 250 | const file = splitFile(content); |
| 251 | const lines = [...file.lines]; |
| 252 | let cursor = 0; |
| 253 | |
| 254 | for (const hunk of hunks) { |
| 255 | if (hunk.changeContext) { |
| 256 | const contextIndex = findSequence(lines, [hunk.changeContext], cursor); |
| 257 | if (contextIndex < 0) { |
| 258 | throw patchError(`could not find hunk context in ${path}: ${hunk.changeContext}`); |
| 259 | } |
| 260 | cursor = contextIndex + 1; |
| 261 | } |
| 262 | |
| 263 | const oldLines = hunk.lines |
| 264 | .filter((line) => line.kind !== "add") |
| 265 | .map((line) => line.text); |
| 266 | const newLines = hunk.lines |
| 267 | .filter((line) => line.kind !== "remove") |
| 268 | .map((line) => line.text); |
| 269 | const index = hunk.endOfFile && oldLines.length === 0 |
| 270 | ? lines.length |
| 271 | : findSequence(lines, oldLines, cursor, hunk.endOfFile); |
| 272 | |
| 273 | if (index < 0) { |
| 274 | const preview = oldLines.slice(0, 3).join("\n"); |
| 275 | throw patchError(`could not find hunk context in ${path}: ${preview}`); |
| 276 | } |
| 277 | |
| 278 | lines.splice(index, oldLines.length, ...newLines); |
| 279 | cursor = index + newLines.length; |
| 280 | } |
| 281 | |
| 282 | const normalized = `${lines.join("\n")}\n`; |
| 283 | return file.eol === "\r\n" ? normalized.replace(/\n/g, "\r\n") : normalized; |
| 284 | } |
| 285 | |
| 286 | async function fileExists(path: string): Promise<boolean> { |
| 287 | try { |
no test coverage detected