( originalLines: string[], filePath: string, chunks: UpdateFileChunk[], )
| 340 | } |
| 341 | |
| 342 | function computeReplacements( |
| 343 | originalLines: string[], |
| 344 | filePath: string, |
| 345 | chunks: UpdateFileChunk[], |
| 346 | ): Array<[number, number, string[]]> { |
| 347 | const replacements: Array<[number, number, string[]]> = [] |
| 348 | let lineIndex = 0 |
| 349 | |
| 350 | for (const chunk of chunks) { |
| 351 | // Handle context-based seeking |
| 352 | if (chunk.change_context) { |
| 353 | const contextIdx = seekSequence(originalLines, [chunk.change_context], lineIndex) |
| 354 | if (contextIdx === -1) { |
| 355 | throw new Error(`Failed to find context '${chunk.change_context}' in ${filePath}`) |
| 356 | } |
| 357 | lineIndex = contextIdx + 1 |
| 358 | } |
| 359 | |
| 360 | // Handle pure addition (no old lines) |
| 361 | if (chunk.old_lines.length === 0) { |
| 362 | const insertionIdx = |
| 363 | originalLines.length > 0 && originalLines[originalLines.length - 1] === "" |
| 364 | ? originalLines.length - 1 |
| 365 | : originalLines.length |
| 366 | replacements.push([insertionIdx, 0, chunk.new_lines]) |
| 367 | continue |
| 368 | } |
| 369 | |
| 370 | // Try to match old lines in the file |
| 371 | let pattern = chunk.old_lines |
| 372 | let newSlice = chunk.new_lines |
| 373 | let found = seekSequence(originalLines, pattern, lineIndex, chunk.is_end_of_file) |
| 374 | |
| 375 | // Retry without trailing empty line if not found |
| 376 | if (found === -1 && pattern.length > 0 && pattern[pattern.length - 1] === "") { |
| 377 | pattern = pattern.slice(0, -1) |
| 378 | if (newSlice.length > 0 && newSlice[newSlice.length - 1] === "") { |
| 379 | newSlice = newSlice.slice(0, -1) |
| 380 | } |
| 381 | found = seekSequence(originalLines, pattern, lineIndex, chunk.is_end_of_file) |
| 382 | } |
| 383 | |
| 384 | if (found !== -1) { |
| 385 | replacements.push([found, pattern.length, newSlice]) |
| 386 | lineIndex = found + pattern.length |
| 387 | } else { |
| 388 | throw new Error(`Failed to find expected lines in ${filePath}:\n${chunk.old_lines.join("\n")}`) |
| 389 | } |
| 390 | } |
| 391 | |
| 392 | // Sort replacements by index to apply in order |
| 393 | replacements.sort((a, b) => a[0] - b[0]) |
| 394 | |
| 395 | return replacements |
| 396 | } |
| 397 | |
| 398 | function applyReplacements(lines: string[], replacements: Array<[number, number, string[]]>): string[] { |
| 399 | // Apply replacements in reverse order to avoid index shifting |
no test coverage detected