diff
Version:
A JavaScript text diff implementation.
64 lines (63 loc) • 3.17 kB
JavaScript
;
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;
}