(patch: string)
| 45 | } |
| 46 | |
| 47 | export function parsePatch(patch: string): PatchAction[] { |
| 48 | const lines = patchLines(patch); |
| 49 | if (lines.shift()?.trim() !== "*** Begin Patch") { |
| 50 | throw patchError("missing *** Begin Patch marker"); |
| 51 | } |
| 52 | if (lines.pop()?.trim() !== "*** End Patch") { |
| 53 | throw patchError("missing *** End Patch marker"); |
| 54 | } |
| 55 | |
| 56 | const actions: PatchAction[] = []; |
| 57 | let index = 0; |
| 58 | |
| 59 | while (index < lines.length) { |
| 60 | const header = lines[index++].trim(); |
| 61 | if (header === "") continue; |
| 62 | |
| 63 | if (header.startsWith("*** Environment ID: ")) { |
| 64 | if (!header.slice("*** Environment ID: ".length).trim()) { |
| 65 | throw patchError("environment id cannot be empty"); |
| 66 | } |
| 67 | continue; |
| 68 | } |
| 69 | |
| 70 | if (header.startsWith("*** Add File: ")) { |
| 71 | const path = header.slice("*** Add File: ".length); |
| 72 | const content: string[] = []; |
| 73 | while (index < lines.length && !isTopLevelHeader(lines[index])) { |
| 74 | const line = lines[index++]; |
| 75 | if (!line.startsWith("+")) { |
| 76 | throw patchError(`added file line must start with +: ${line}`); |
| 77 | } |
| 78 | content.push(line.slice(1)); |
| 79 | } |
| 80 | if (content.length === 0) throw patchError(`add file for ${path} has no content`); |
| 81 | actions.push({ |
| 82 | kind: "add", |
| 83 | path, |
| 84 | content: `${content.join("\n")}\n`, |
| 85 | }); |
| 86 | continue; |
| 87 | } |
| 88 | |
| 89 | if (header.startsWith("*** Delete File: ")) { |
| 90 | actions.push({ kind: "delete", path: header.slice("*** Delete File: ".length) }); |
| 91 | continue; |
| 92 | } |
| 93 | |
| 94 | if (header.startsWith("*** Update File: ")) { |
| 95 | const path = header.slice("*** Update File: ".length); |
| 96 | let moveTo: string | undefined; |
| 97 | const hunks: UpdateHunk[] = []; |
| 98 | |
| 99 | if (lines[index]?.trim().startsWith("*** Move to: ")) { |
| 100 | moveTo = lines[index++].trim().slice("*** Move to: ".length); |
| 101 | } |
| 102 | |
| 103 | let current: UpdateHunk | undefined; |
| 104 | const finishCurrent = (): void => { |
no test coverage detected