(
edits: { path: string; content: string }[],
readFileIfExists: (path: string) => Promise<string | null>,
writeFile: (path: string, content: string) => Promise<void>,
deleteFile: (path: string) => Promise<void>,
options: StateApplyEditsOptions = {}
)
| 298 | } |
| 299 | |
| 300 | export async function applyTextEdits( |
| 301 | edits: { path: string; content: string }[], |
| 302 | readFileIfExists: (path: string) => Promise<string | null>, |
| 303 | writeFile: (path: string, content: string) => Promise<void>, |
| 304 | deleteFile: (path: string) => Promise<void>, |
| 305 | options: StateApplyEditsOptions = {} |
| 306 | ): Promise<StateApplyEditsResult> { |
| 307 | const results: StateAppliedEditResult[] = []; |
| 308 | let totalChanged = 0; |
| 309 | const appliedSnapshots: Array<{ path: string; previous: string | null }> = []; |
| 310 | |
| 311 | try { |
| 312 | for (const edit of edits) { |
| 313 | const previous = await readFileIfExists(edit.path); |
| 314 | const nextContent = edit.content; |
| 315 | const changed = previous !== nextContent; |
| 316 | |
| 317 | if (changed && !options.dryRun) { |
| 318 | await writeFile(edit.path, nextContent); |
| 319 | appliedSnapshots.push({ path: edit.path, previous }); |
| 320 | } |
| 321 | |
| 322 | results.push({ |
| 323 | path: edit.path, |
| 324 | changed, |
| 325 | content: nextContent, |
| 326 | diff: changed |
| 327 | ? diffContent(previous ?? "", nextContent, edit.path, edit.path) |
| 328 | : "" |
| 329 | }); |
| 330 | |
| 331 | if (changed) { |
| 332 | totalChanged++; |
| 333 | } |
| 334 | } |
| 335 | } catch (error) { |
| 336 | const rollback = options.rollbackOnError ?? true; |
| 337 | const rollbackError = rollback |
| 338 | ? await rollbackSnapshots(appliedSnapshots, writeFile, deleteFile) |
| 339 | : undefined; |
| 340 | throw new StateBatchOperationError({ |
| 341 | operation: "applyEdits", |
| 342 | message: error instanceof Error ? error.message : String(error), |
| 343 | rolledBack: rollback, |
| 344 | rollbackError |
| 345 | }); |
| 346 | } |
| 347 | |
| 348 | return { |
| 349 | dryRun: options.dryRun ?? false, |
| 350 | edits: results, |
| 351 | totalChanged |
| 352 | }; |
| 353 | } |
| 354 | |
| 355 | export async function planTextEdits( |
| 356 | instructions: StateEditInstruction[], |
no test coverage detected