@sussudio/platform
Version:
Internal APIs for VS Code's service injection the base services.
100 lines (99 loc) • 3.54 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export function merge(local, remote, lastSync, ignored) {
const localResult = { added: [], removed: [], updated: [] };
let remoteResult = { added: [], removed: [], updated: [] };
if (!remote) {
const added = local.filter(({ id }) => !ignored.includes(id));
if (added.length) {
remoteResult.added = added;
} else {
remoteResult = null;
}
return {
local: localResult,
remote: remoteResult,
};
}
const localToRemote = compare(local, remote, ignored);
if (localToRemote.added.length > 0 || localToRemote.removed.length > 0 || localToRemote.updated.length > 0) {
const baseToLocal = compare(lastSync, local, ignored);
const baseToRemote = compare(lastSync, remote, ignored);
// Remotely removed profiles
for (const id of baseToRemote.removed) {
const e = local.find((profile) => profile.id === id);
if (e) {
localResult.removed.push(e);
}
}
// Remotely added profiles
for (const id of baseToRemote.added) {
const remoteProfile = remote.find((profile) => profile.id === id);
// Got added in local
if (baseToLocal.added.includes(id)) {
// Is different from local to remote
if (localToRemote.updated.includes(id)) {
// Remote wins always
localResult.updated.push(remoteProfile);
}
} else {
localResult.added.push(remoteProfile);
}
}
// Remotely updated profiles
for (const id of baseToRemote.updated) {
// Remote wins always
localResult.updated.push(remote.find((profile) => profile.id === id));
}
// Locally added profiles
for (const id of baseToLocal.added) {
// Not there in remote
if (!baseToRemote.added.includes(id)) {
remoteResult.added.push(local.find((profile) => profile.id === id));
}
}
// Locally updated profiles
for (const id of baseToLocal.updated) {
// If removed in remote
if (baseToRemote.removed.includes(id)) {
continue;
}
// If not updated in remote
if (!baseToRemote.updated.includes(id)) {
remoteResult.updated.push(local.find((profile) => profile.id === id));
}
}
// Locally removed profiles
for (const id of baseToLocal.removed) {
const removedProfile = remote.find((profile) => profile.id === id);
if (removedProfile) {
remoteResult.removed.push(removedProfile);
}
}
}
if (remoteResult.added.length === 0 && remoteResult.removed.length === 0 && remoteResult.updated.length === 0) {
remoteResult = null;
}
return { local: localResult, remote: remoteResult };
}
function compare(from, to, ignoredProfiles) {
from = from ? from.filter(({ id }) => !ignoredProfiles.includes(id)) : [];
to = to.filter(({ id }) => !ignoredProfiles.includes(id));
const fromKeys = from.map(({ id }) => id);
const toKeys = to.map(({ id }) => id);
const added = toKeys.filter((key) => fromKeys.indexOf(key) === -1);
const removed = fromKeys.filter((key) => toKeys.indexOf(key) === -1);
const updated = [];
for (const { id, name, shortName } of from) {
if (removed.includes(id)) {
continue;
}
const toProfile = to.find((p) => p.id === id);
if (!toProfile || toProfile.name !== name || toProfile.shortName !== shortName) {
updated.push(id);
}
}
return { added, removed, updated };
}