(root: string, patch: string)
| 315 | } |
| 316 | |
| 317 | export async function applyPatch(root: string, patch: string): Promise<ApplyPatchResult> { |
| 318 | const actions = parsePatch(patch); |
| 319 | const results: AppliedPatchFile[] = []; |
| 320 | const patches: string[] = []; |
| 321 | |
| 322 | for (const action of actions) { |
| 323 | if (action.kind === "add") { |
| 324 | const absolute = await resolveConfinedPath(root, action.path); |
| 325 | const original = await readOptionalTextFile(absolute, action.path); |
| 326 | await writeTextFile(absolute, action.content, original?.mode); |
| 327 | patches.push(unifiedFilePatch(action.path, action.path, original?.content ?? null, action.content)); |
| 328 | results.push({ path: action.path, operation: "add" }); |
| 329 | continue; |
| 330 | } |
| 331 | |
| 332 | const absolute = await resolveConfinedPath(root, action.path); |
| 333 | const file = await readRequiredTextFile(absolute, action.path); |
| 334 | |
| 335 | if (action.kind === "delete") { |
| 336 | await rm(absolute); |
| 337 | patches.push(unifiedFilePatch(action.path, action.path, file.content, null)); |
| 338 | results.push({ path: action.path, operation: "delete" }); |
| 339 | continue; |
| 340 | } |
| 341 | |
| 342 | const updated = applyHunks(action.path, file.content, action.hunks); |
| 343 | if (action.moveTo) { |
| 344 | const destination = await resolveConfinedPath(root, action.moveTo); |
| 345 | if (destination !== absolute) await readOptionalTextFile(destination, action.moveTo); |
| 346 | await writeTextFile(destination, updated, file.mode); |
| 347 | if (destination !== absolute) await rm(absolute); |
| 348 | patches.push(unifiedFilePatch(action.path, action.moveTo, file.content, updated)); |
| 349 | results.push({ path: action.moveTo, previousPath: action.path, operation: "move" }); |
| 350 | } else { |
| 351 | await writeTextFile(absolute, updated, file.mode); |
| 352 | patches.push(unifiedFilePatch(action.path, action.path, file.content, updated)); |
| 353 | results.push({ path: action.path, operation: "update" }); |
| 354 | } |
| 355 | } |
| 356 | |
| 357 | const unifiedPatch = patches.filter(Boolean).join("\n"); |
| 358 | const stats = countPatchStats(unifiedPatch); |
| 359 | return { files: results, patch: unifiedPatch, ...stats }; |
| 360 | } |
| 361 | |
| 362 | async function readRequiredTextFile(absolute: string, displayPath: string): Promise<TextFile> { |
| 363 | if (!(await fileExists(absolute))) throw patchError(`file does not exist: ${displayPath}`); |
no test coverage detected