| "use strict"; | |
| Object.defineProperty(exports, "__esModule", { value: true }); | |
| exports.reversePatch = reversePatch; | |
| function swapPrefix(fileName) { | |
| if (fileName === undefined || fileName === '/dev/null') { | |
| return fileName; | |
| } | |
| if (fileName.startsWith('a/')) { | |
| return 'b/' + fileName.slice(2); | |
| } | |
| if (fileName.startsWith('b/')) { | |
| return 'a/' + fileName.slice(2); | |
| } | |
| return fileName; | |
| } | |
| function reversePatch(structuredPatch) { | |
| if (Array.isArray(structuredPatch)) { | |
| // (See comment in unixToWin for why we need the pointless-looking anonymous function here) | |
| return structuredPatch.map(patch => reversePatch(patch)).reverse(); | |
| } | |
| const reversed = Object.assign(Object.assign({}, structuredPatch), { oldFileName: structuredPatch.isGit ? swapPrefix(structuredPatch.newFileName) : structuredPatch.newFileName, oldHeader: structuredPatch.newHeader, newFileName: structuredPatch.isGit ? swapPrefix(structuredPatch.oldFileName) : structuredPatch.oldFileName, newHeader: structuredPatch.oldHeader, oldMode: structuredPatch.newMode, newMode: structuredPatch.oldMode, isCreate: structuredPatch.isDelete, isDelete: structuredPatch.isCreate, hunks: structuredPatch.hunks.map(hunk => { | |
| return { | |
| oldLines: hunk.newLines, | |
| oldStart: hunk.newStart, | |
| newLines: hunk.oldLines, | |
| newStart: hunk.oldStart, | |
| lines: hunk.lines.map(l => { | |
| if (l.startsWith('-')) { | |
| return `+${l.slice(1)}`; | |
| } | |
| if (l.startsWith('+')) { | |
| return `-${l.slice(1)}`; | |
| } | |
| return l; | |
| }) | |
| }; | |
| }) }); | |
| if (structuredPatch.isCopy) { | |
| // Reversing a copy means deleting the file that was created by the copy. | |
| // The "old" file in the reversed patch is the copy destination (which | |
| // exists and should be removed), and the "new" file is /dev/null. | |
| // | |
| // Note: we clear the hunks because the original copy's hunks describe | |
| // the diff between the source and destination, not the full content of | |
| // the destination file, so they can't be meaningfully reversed into a | |
| // deletion hunk. This means the resulting patch is not something | |
| // `git apply` will accept (it requires deletion patches to include a | |
| // hunk removing every line). Producing a correct deletion hunk would | |
| // require knowing the full content of the copy destination, which we | |
| // don't have. Consumers that need a `git apply`-compatible patch will | |
| // need to resolve the full file content themselves. | |
| reversed.newFileName = '/dev/null'; | |
| reversed.newHeader = undefined; | |
| reversed.isDelete = true; | |
| delete reversed.isCreate; | |
| delete reversed.isCopy; | |
| delete reversed.isRename; | |
| reversed.hunks = []; | |
| } | |
| // Reversing a rename is just a rename in the opposite direction; | |
| // isRename stays set and the filenames are already swapped above. | |
| return reversed; | |
| } |