git-documentdb
Version:
Offline-first database that syncs with Git
757 lines • 31.1 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.threeWayMerge = exports.merge = void 0;
const path_1 = __importStar(require("path"));
const isomorphic_git_1 = __importDefault(require("isomorphic-git"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const const_1 = require("../const");
const error_1 = require("../error");
const worker_utils_1 = require("./worker_utils");
const utils_1 = require("../utils");
const blob_1 = require("../crud/blob");
/**
* @internal
*/
function getStrategy(strategy, oursDoc, theirsDoc) {
const defaultStrategy = const_1.DEFAULT_CONFLICT_RESOLUTION_STRATEGY;
if (strategy === undefined) {
strategy = defaultStrategy;
}
else if (strategy !== 'ours-diff' &&
strategy !== 'theirs-diff' &&
strategy !== 'ours' &&
strategy !== 'theirs') {
// Strategy may be a function
strategy = strategy(oursDoc, theirsDoc);
if (strategy === undefined) {
strategy = defaultStrategy;
}
}
return strategy;
}
/**
* @throws {@link Err.InvalidConflictResolutionStrategyError}
*
* @internal
*/
function getMergedJsonDoc(jsonDiff, jsonPatch, strategy, base, ours, theirs, serializeFormat) {
let result;
if (strategy === 'ours') {
result = ours;
}
else if (strategy === 'theirs') {
result = theirs;
}
else if (strategy === 'ours-diff') {
result = jsonPatch.patch(ours, jsonDiff.diff(base, ours), theirs, jsonDiff.diff(base, theirs), strategy);
}
else if (strategy === 'theirs-diff') {
result = jsonPatch.patch(ours, jsonDiff.diff(base, ours), theirs, jsonDiff.diff(base, theirs), strategy);
}
else {
throw new error_1.Err.InvalidConflictResolutionStrategyError();
}
return serializeFormat.serialize(result).data;
}
/**
* @throws {@link Err.InvalidConflictResolutionStrategyError}
*
* @internal
*/
function getMergedTextDoc(strategy, base, ours, theirs) {
if (strategy === 'ours') {
return ours;
}
else if (strategy === 'theirs') {
return theirs;
}
else if (strategy === 'ours-diff') {
// TODO: implement diff and patch
return ours;
}
else if (strategy === 'theirs-diff') {
// TODO: implement diff and patch
return theirs;
}
throw new error_1.Err.InvalidConflictResolutionStrategyError();
}
/**
* @throws {@link Err.InvalidConflictResolutionStrategyError}
*
* @internal
*/
function getMergedBinaryDoc(strategy, ours, theirs) {
if (strategy === 'ours') {
return ours;
}
else if (strategy === 'theirs') {
return theirs;
}
throw new error_1.Err.InvalidConflictResolutionStrategyError();
}
/**
* getMergedDocument
*
* @throws {@link Err.InvalidDocTypeError}
*
* @throws # Errors from getMergedJsonDoc, getMergedTextDoc, getMergedBinaryDoc
* @throws - {@link Err.InvalidConflictResolutionStrategyError}
*
* @internal
*/
function getMergedDocument(jsonDiff, jsonPatch, strategy, base, ours, theirs, docType, serializeFormat, extension = '') {
if (docType === 'json') {
const oursDoc = (0, blob_1.textToJsonDoc)((0, utils_1.utf8decode)(ours), serializeFormat, extension);
const theirsDoc = (0, blob_1.textToJsonDoc)((0, utils_1.utf8decode)(theirs), serializeFormat, extension);
let baseDoc;
if (base) {
baseDoc = (0, blob_1.textToJsonDoc)((0, utils_1.utf8decode)(base), serializeFormat, extension);
}
else {
baseDoc = undefined;
}
return getMergedJsonDoc(jsonDiff, jsonPatch, strategy, baseDoc, oursDoc, theirsDoc, serializeFormat);
}
else if (docType === 'text') {
const oursDoc = (0, utils_1.utf8decode)(ours);
const theirsDoc = (0, utils_1.utf8decode)(theirs);
let baseDoc;
if (base) {
baseDoc = (0, utils_1.utf8decode)(base);
}
else {
baseDoc = undefined;
}
return getMergedTextDoc(strategy, baseDoc, oursDoc, theirsDoc);
}
else if (docType === 'binary') {
return getMergedBinaryDoc(strategy, ours, theirs);
}
throw new error_1.Err.InvalidDocTypeError(docType);
}
/**
* merge
*
* @throws Errors from {@link threeWayMerge}
*
* @internal
*/
async function merge(gitDDB, sync, baseCommitOid, oursCommitOid, theirsCommitOid) {
const acceptedConflicts = [];
const localChanges = [];
const remoteChanges = [];
const strategy = sync.options.conflictResolutionStrategy;
const results = await isomorphic_git_1.default.walk({
fs: fs_extra_1.default,
dir: gitDDB.workingDir,
trees: [
isomorphic_git_1.default.TREE({ ref: baseCommitOid }),
isomorphic_git_1.default.TREE({ ref: oursCommitOid }),
isomorphic_git_1.default.TREE({ ref: theirsCommitOid }),
],
// @ts-ignore
// eslint-disable-next-line complexity
map: async function (fullDocPath, [base, ours, theirs]) {
const baseType = base === null ? undefined : await base.type();
if (baseType === 'tree') {
return {
mode: (await base.mode()).toString(8),
path: (0, path_1.basename)(fullDocPath),
oid: await base.oid(),
type: await base.type(),
};
}
const oursType = ours === null ? undefined : await ours.type();
if (oursType === 'tree') {
return {
mode: (await ours.mode()).toString(8),
path: (0, path_1.basename)(fullDocPath),
oid: await ours.oid(),
type: await ours.type(),
};
}
const theirsType = theirs === null ? undefined : await theirs.type();
if (theirsType === 'tree') {
return {
mode: (await theirs.mode()).toString(8),
path: (0, path_1.basename)(fullDocPath),
oid: await theirs.oid(),
type: await theirs.type(),
};
}
const [treeEntry, localChange, remoteChange, conflict] = await threeWayMerge(gitDDB, sync, strategy, fullDocPath, base, ours, theirs);
if (localChange !== undefined) {
localChanges.push(localChange);
}
if (remoteChange !== undefined) {
remoteChanges.push(remoteChange);
}
if (conflict !== undefined) {
acceptedConflicts.push(conflict);
}
if (treeEntry === undefined) {
return;
}
return treeEntry;
},
reduce: async (parent, children) => {
if (!parent)
return;
if (parent.type === 'tree') {
if (children.length === 0)
return;
const newTreeOid = await isomorphic_git_1.default.writeTree({
fs: fs_extra_1.default,
dir: gitDDB.workingDir,
tree: children,
});
// eslint-disable-next-line require-atomic-updates
parent.oid = newTreeOid;
}
return parent;
},
});
const mergedTreeOid = results.oid;
// Entries in walk are traversed in alphabetical order
// (https://isomorphic-git.org/docs/en/walk),
// but sometimes the order collapse.
// eslint-disable-next-line complexity
const sortChangedFile = (a, b) => {
if (a.operation === 'insert' && b.operation === 'insert') {
if (a.new.name > b.new.name)
return 1;
if (a.new.name < b.new.name)
return -1;
return 0;
}
else if ((a.operation === 'update' || a.operation === 'delete') &&
(b.operation === 'update' || b.operation === 'delete')) {
if (a.old.name > b.old.name)
return 1;
if (a.old.name < b.old.name)
return -1;
return 0;
}
// This line must not be reached.
return 0;
};
localChanges.sort(sortChangedFile);
remoteChanges.sort(sortChangedFile);
return [mergedTreeOid, localChanges, remoteChanges, acceptedConflicts];
}
exports.merge = merge;
/**
* 3-way merge
*
* @throws {@link Err.InvalidConflictStateError}
* @throws {@link Err.CannotDeleteDataError}
*
* @throws # Errors from getMergedDocument
* @throws - {@link Err.InvalidDocTypeError}
* @throws - {@link Err.InvalidConflictResolutionStrategyError}
*
* @throws # Errors from writeBlobToFile
* @throws - {@link Err.CannotCreateDirectoryError}
*
* @throws # Errors from getFatDocFromData, getFatDocFromReadBlobResult
* @throws - {@link Err.InvalidJsonObjectError}
*
*/
// eslint-disable-next-line complexity
async function threeWayMerge(gitDDB, sync, conflictResolutionStrategy, fullDocPath, base, ours, theirs) {
const docType = gitDDB.serializeFormat.hasObjectExtension(fullDocPath)
? 'json'
: 'text';
if (docType === 'text') {
// TODO: select binary or text by .gitattribtues
}
// 2 x 2 x 2 cases
if (!base && !ours && !theirs) {
// This case must not occurred.
throw new error_1.Err.InvalidConflictStateError('Neither a base entry nor a local entry nor a remote entry exists.');
}
else if (!base && !ours && theirs) {
// A new file has been inserted into theirs.
// Write it to the working directory.
// Write it to the index.
// console.log(' #case 1 - Accept theirs (insert): ' + fullDocPath);
const theirsData = (await theirs.content());
const theirsFatDoc = await (0, worker_utils_1.getFatDocFromData)(theirsData, fullDocPath, docType, gitDDB.serializeFormat);
await (0, worker_utils_1.writeBlobToFile)(gitDDB.workingDir, fullDocPath, theirsData);
await isomorphic_git_1.default.add({ fs: fs_extra_1.default, dir: gitDDB.workingDir, filepath: fullDocPath });
return [
{
mode: (await theirs.mode()).toString(8),
path: (0, path_1.basename)(fullDocPath),
oid: await theirs.oid(),
type: 'blob',
},
{
operation: 'insert',
new: theirsFatDoc,
},
undefined,
undefined,
];
}
else if (!base && ours && !theirs) {
// A new file has been inserted into ours.
// It has already been created on the working directory.
// It has already been added to the index.
// console.log(' #case 2 - Accept ours (insert): ' + fullDocPath);
const oursData = (await ours.content());
const oursFatDoc = await (0, worker_utils_1.getFatDocFromData)(oursData, fullDocPath, docType, gitDDB.serializeFormat);
return [
{
mode: (await ours.mode()).toString(8),
path: (0, path_1.basename)(fullDocPath),
oid: await ours.oid(),
type: 'blob',
},
undefined,
{
operation: 'insert',
new: oursFatDoc,
},
undefined,
];
}
else if (!base && ours && theirs) {
const oursOid = await ours.oid();
const theirsOid = await theirs.oid();
const oursMode = (await ours.mode()).toString(8);
const theirsMode = (await theirs.mode()).toString(8);
if (oursOid === theirsOid && oursMode === theirsMode) {
// The same filenames with exactly the same contents are inserted on both local and remote.
// It has already been created on the both working directory.
// It has already been added to the both index.
// console.log(' #case 3 - Accept both (insert): ' + fullDocPath);
return [
{
mode: oursMode,
path: (0, path_1.basename)(fullDocPath),
oid: oursOid,
type: 'blob',
},
undefined,
undefined,
undefined,
];
}
// ! Conflict
const oursData = (await ours.content());
const theirsData = (await theirs.content());
const oursFatDoc = await (0, worker_utils_1.getFatDocFromData)(oursData, fullDocPath, docType, gitDDB.serializeFormat);
const theirsFatDoc = await (0, worker_utils_1.getFatDocFromData)(theirsData, fullDocPath, docType, gitDDB.serializeFormat);
const strategy = await getStrategy(conflictResolutionStrategy, oursFatDoc, theirsFatDoc);
let mode = '';
if (strategy === 'ours' || strategy === 'ours-diff') {
// console.log(' #case 4 - Conflict. Accept ours (insert): ' + fullDocPath);
mode = oursMode;
}
else if (strategy === 'theirs' || strategy === 'theirs-diff') {
// console.log(' #case 5 - Conflict. Accept theirs (insert): ' + fullDocPath);
mode = theirsMode;
}
let resultFatDoc;
let localChange;
let remoteChange;
if (strategy === 'ours') {
// Can skip getMergedDocument().
resultFatDoc = oursFatDoc;
localChange = undefined;
remoteChange = {
operation: 'update',
old: theirsFatDoc,
new: oursFatDoc,
};
}
else if (strategy === 'theirs') {
// Can skip getMergedDocument().
resultFatDoc = theirsFatDoc;
await (0, worker_utils_1.writeBlobToFile)(gitDDB.workingDir, fullDocPath, theirsData);
await isomorphic_git_1.default.add({ fs: fs_extra_1.default, dir: gitDDB.workingDir, filepath: fullDocPath });
localChange = {
operation: 'update',
old: oursFatDoc,
new: theirsFatDoc,
};
remoteChange = undefined;
}
else {
// Diff and patch
const extensionMatch = fullDocPath.match(/.+(\..+?)$/);
let extension = '';
if (extensionMatch) {
extension = extensionMatch[1];
}
const data = await getMergedDocument(sync.jsonDiff, sync.jsonPatch, strategy, undefined, oursData, theirsData, docType, gitDDB.serializeFormat, extension);
resultFatDoc = await (0, worker_utils_1.getFatDocFromData)(data, fullDocPath, docType, gitDDB.serializeFormat);
await (0, worker_utils_1.writeBlobToFile)(gitDDB.workingDir, fullDocPath, data);
await isomorphic_git_1.default.add({ fs: fs_extra_1.default, dir: gitDDB.workingDir, filepath: fullDocPath });
if (!(0, blob_1.isSameFatDoc)(oursFatDoc, resultFatDoc)) {
localChange = {
operation: 'update',
old: oursFatDoc,
new: resultFatDoc,
};
}
if (!(0, blob_1.isSameFatDoc)(theirsFatDoc, resultFatDoc)) {
remoteChange = {
operation: 'update',
old: theirsFatDoc,
new: resultFatDoc,
};
}
}
const acceptedConflict = {
fatDoc: resultFatDoc,
strategy,
operation: strategy.endsWith('-diff') ? 'insert-merge' : 'insert',
};
return [
{
mode,
path: (0, path_1.basename)(fullDocPath),
oid: resultFatDoc.fileOid,
type: 'blob',
},
localChange,
remoteChange,
acceptedConflict,
];
}
else if (base && !ours && !theirs) {
// The same files have been removed from both local and remote.
// console.log(' #case 6 - Accept both (delete): ' + fullDocPath);
return [undefined, undefined, undefined, undefined];
}
else if (base && !ours && theirs) {
const baseOid = await base.oid();
const theirsOid = await theirs.oid();
const theirsData = (await theirs.content());
const theirsFatDoc = await (0, worker_utils_1.getFatDocFromData)(theirsData, fullDocPath, docType, gitDDB.serializeFormat);
if (baseOid === theirsOid) {
// A file has been removed from ours.
// console.log(' #case 7 - Accept ours (delete): ' + fullDocPath);
return [
undefined,
undefined,
{
operation: 'delete',
old: theirsFatDoc,
},
undefined,
];
}
// ! Conflict
const strategy = await getStrategy(conflictResolutionStrategy, undefined, theirsFatDoc);
if (strategy === 'ours' || strategy === 'ours-diff') {
// console.log(' #case 8 - Conflict. Accept ours (delete): ' + fullDocPath);
const baseData = (await base.content());
const baseFatDoc = await (0, worker_utils_1.getFatDocFromData)(baseData, fullDocPath, docType, gitDDB.serializeFormat);
const acceptedConflict = {
fatDoc: baseFatDoc,
strategy: strategy,
operation: 'delete',
};
return [
undefined,
undefined,
{
operation: 'delete',
old: theirsFatDoc,
},
acceptedConflict,
];
}
else if (strategy === 'theirs' || strategy === 'theirs-diff') {
// console.log(' #case 9 - Conflict. Accept theirs (update): ' + fullDocPath);
const acceptedConflict = {
fatDoc: theirsFatDoc,
strategy: strategy,
operation: 'update',
};
await (0, worker_utils_1.writeBlobToFile)(gitDDB.workingDir, fullDocPath, theirsData);
await isomorphic_git_1.default.add({ fs: fs_extra_1.default, dir: gitDDB.workingDir, filepath: fullDocPath });
return [
{
mode: (await theirs.mode()).toString(8),
path: (0, path_1.basename)(fullDocPath),
oid: theirsFatDoc.fileOid,
type: 'blob',
},
{
operation: 'insert',
new: theirsFatDoc,
},
undefined,
acceptedConflict,
];
}
}
else if (base && ours && !theirs) {
const baseOid = await base.oid();
const oursOid = await ours.oid();
const oursData = (await ours.content());
const oursFatDoc = await (0, worker_utils_1.getFatDocFromData)(oursData, fullDocPath, docType, gitDDB.serializeFormat);
if (baseOid === oursOid) {
// A file has been removed from theirs.
// console.log(' #case 10 - Accept theirs (delete): ' + fullDocPath);
await fs_extra_1.default.remove(path_1.default.resolve(gitDDB.workingDir, fullDocPath)).catch(() => {
throw new error_1.Err.CannotDeleteDataError();
});
await isomorphic_git_1.default.remove({ fs: fs_extra_1.default, dir: gitDDB.workingDir, filepath: fullDocPath });
return [
undefined,
{
operation: 'delete',
old: oursFatDoc,
},
undefined,
undefined,
];
}
// ! Conflict
const strategy = await getStrategy(conflictResolutionStrategy, oursFatDoc, undefined);
if (strategy === 'ours' || strategy === 'ours-diff') {
// console.log(' #case 11 - Conflict. Accept ours (update): ' + fullDocPath);
const acceptedConflict = {
fatDoc: oursFatDoc,
strategy: strategy,
operation: 'update',
};
return [
{
mode: (await ours.mode()).toString(8),
path: (0, path_1.basename)(fullDocPath),
oid: oursOid,
type: 'blob',
},
undefined,
{
operation: 'insert',
new: oursFatDoc,
},
acceptedConflict,
];
}
else if (strategy === 'theirs' || strategy === 'theirs-diff') {
// console.log(' #case 12 - Conflict. Accept theirs (delete): ' + fullDocPath);
const baseData = (await base.content());
const baseFatDoc = await (0, worker_utils_1.getFatDocFromData)(baseData, fullDocPath, docType, gitDDB.serializeFormat);
const acceptedConflicts = {
fatDoc: baseFatDoc,
strategy: strategy,
operation: 'delete',
};
await fs_extra_1.default.remove(path_1.default.resolve(gitDDB.workingDir, fullDocPath)).catch(() => {
throw new error_1.Err.CannotDeleteDataError();
});
await isomorphic_git_1.default.remove({ fs: fs_extra_1.default, dir: gitDDB.workingDir, filepath: fullDocPath });
return [
undefined,
{
operation: 'delete',
old: oursFatDoc,
},
undefined,
acceptedConflicts,
];
}
}
else if (base && ours && theirs) {
const baseOid = await base.oid();
const oursOid = await ours.oid();
const theirsOid = await theirs.oid();
if (oursOid === theirsOid) {
// The same filenames with exactly the same contents are inserted into both local and remote.
// console.log(' #case 13 - Accept both (update): ' + fullDocPath);
return [
{
// TODO: check whether mode is the same.
mode: (await ours.mode()).toString(8),
path: (0, path_1.basename)(fullDocPath),
oid: oursOid,
type: 'blob',
},
undefined,
undefined,
undefined,
];
}
else if (baseOid === oursOid) {
// console.log(' #case 14 - Accept theirs (update): ' + fullDocPath);
const oursData = (await ours.content());
const oursFatDoc = await (0, worker_utils_1.getFatDocFromData)(oursData, fullDocPath, docType, gitDDB.serializeFormat);
const theirsData = (await theirs.content());
const theirsFatDoc = await (0, worker_utils_1.getFatDocFromData)(theirsData, fullDocPath, docType, gitDDB.serializeFormat);
await (0, worker_utils_1.writeBlobToFile)(gitDDB.workingDir, fullDocPath, theirsData);
await isomorphic_git_1.default.add({ fs: fs_extra_1.default, dir: gitDDB.workingDir, filepath: fullDocPath });
return [
{
mode: (await theirs.mode()).toString(8),
path: (0, path_1.basename)(fullDocPath),
oid: theirsFatDoc.fileOid,
type: 'blob',
},
{
operation: 'update',
old: oursFatDoc,
new: theirsFatDoc,
},
undefined,
undefined,
];
}
else if (baseOid === theirsOid) {
// console.log(' #case 15 - Accept ours (update): ' + fullDocPath);
const oursData = (await ours.content());
const oursFatDoc = await (0, worker_utils_1.getFatDocFromData)(oursData, fullDocPath, docType, gitDDB.serializeFormat);
const theirsData = (await theirs.content());
const theirsFatDoc = await (0, worker_utils_1.getFatDocFromData)(theirsData, fullDocPath, docType, gitDDB.serializeFormat);
return [
{
mode: (await theirs.mode()).toString(8),
path: (0, path_1.basename)(fullDocPath),
oid: oursFatDoc.fileOid,
type: 'blob',
},
undefined,
{
operation: 'update',
old: theirsFatDoc,
new: oursFatDoc,
},
undefined,
];
}
// ! Conflict
const baseData = (await base.content());
const oursData = (await ours.content());
const theirsData = (await theirs.content());
const oursFatDoc = await (0, worker_utils_1.getFatDocFromData)(oursData, fullDocPath, docType, gitDDB.serializeFormat);
const theirsFatDoc = await (0, worker_utils_1.getFatDocFromData)(theirsData, fullDocPath, docType, gitDDB.serializeFormat);
const strategy = await getStrategy(conflictResolutionStrategy, oursFatDoc, theirsFatDoc);
if (strategy === 'ours') {
// console.log(' #case 16 - Conflict. Accept ours (update): ' + fullDocPath);
return [
{
mode: (await ours.mode()).toString(8),
path: (0, path_1.basename)(fullDocPath),
oid: oursFatDoc.fileOid,
type: 'blob',
},
undefined,
{
operation: 'update',
old: theirsFatDoc,
new: oursFatDoc,
},
{
fatDoc: oursFatDoc,
strategy: strategy,
operation: 'update',
},
];
}
else if (strategy === 'theirs') {
// console.log(' #case 17 - Conflict. Accept theirs (update): ' + fullDocPath);
await (0, worker_utils_1.writeBlobToFile)(gitDDB.workingDir, fullDocPath, theirsData);
await isomorphic_git_1.default.add({ fs: fs_extra_1.default, dir: gitDDB.workingDir, filepath: fullDocPath });
return [
{
mode: (await theirs.mode()).toString(8),
path: (0, path_1.basename)(fullDocPath),
oid: theirsFatDoc.fileOid,
type: 'blob',
},
{
operation: 'update',
old: oursFatDoc,
new: theirsFatDoc,
},
undefined,
{
fatDoc: theirsFatDoc,
strategy: strategy,
operation: 'update',
},
];
}
const extensionMatch = fullDocPath.match(/.+(\..+?)$/);
let extension = '';
if (extensionMatch) {
extension = extensionMatch[1];
}
const data = await getMergedDocument(sync.jsonDiff, sync.jsonPatch, strategy, baseData, oursData, theirsData, docType, gitDDB.serializeFormat, extension);
const resultFatDoc = await (0, worker_utils_1.getFatDocFromData)(data, fullDocPath, docType, gitDDB.serializeFormat);
await (0, worker_utils_1.writeBlobToFile)(gitDDB.workingDir, fullDocPath, data);
await isomorphic_git_1.default.add({ fs: fs_extra_1.default, dir: gitDDB.workingDir, filepath: fullDocPath });
let mode = '';
if (strategy === 'ours-diff') {
// console.log(' #case 16 (diff) - Conflict. Accept ours (update): ' + fullDocPath);
mode = (await ours.mode()).toString(8);
}
else if (strategy === 'theirs-diff') {
// console.log(' #case 17 (diff) - Conflict. Accept theirs (update): ' + fullDocPath);
mode = (await theirs.mode()).toString(8);
}
let localChange;
let remoteChange;
if (!(0, blob_1.isSameFatDoc)(oursFatDoc, resultFatDoc)) {
localChange = {
operation: 'update',
old: oursFatDoc,
new: resultFatDoc,
};
}
if (!(0, blob_1.isSameFatDoc)(theirsFatDoc, resultFatDoc)) {
remoteChange = {
operation: 'update',
old: theirsFatDoc,
new: resultFatDoc,
};
}
return [
{
mode,
path: (0, path_1.basename)(fullDocPath),
oid: resultFatDoc.fileOid,
type: 'blob',
},
localChange,
remoteChange,
{
fatDoc: resultFatDoc,
strategy: strategy,
operation: 'update-merge',
},
];
}
throw new error_1.Err.InvalidConflictStateError('Invalid case');
}
exports.threeWayMerge = threeWayMerge;
//# sourceMappingURL=3way_merge.js.map