Superdiff provides a complete and readable diff for both arrays and objects. Plus, it supports stream and file inputs for handling large datasets efficiently, is battle-tested, has zero dependencies, and is super fast.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

99 lines
2.3 KiB

import { STATUS, ListDiff, ListData, DiffStatus } from "./model";
2 years ago
import { isEqual } from "./utils";
function formatSingleListDiff(
listData: ListData[],
status: DiffStatus
2 years ago
): ListDiff {
return {
type: "list",
status,
diff: listData.map((data: ListData, i) => ({
value: data,
prevIndex: status === STATUS.ADDED ? null : i,
newIndex: status === STATUS.ADDED ? i : null,
indexDiff: null,
status,
})),
2 years ago
};
}
function getListStatus(listDiff: ListDiff["diff"]): DiffStatus {
return listDiff.some((value) => value.status !== STATUS.EQUAL)
? STATUS.UPDATED
: STATUS.EQUAL;
}
2 years ago
export const getListDiff = (
prevList: ListData[] | undefined | null,
nextList: ListData[] | undefined | null
): ListDiff => {
if (!prevList && !nextList) {
return {
type: "list",
status: STATUS.EQUAL,
2 years ago
diff: [],
};
}
if (!prevList) {
return formatSingleListDiff(nextList as ListData, STATUS.ADDED);
2 years ago
}
if (!nextList) {
return formatSingleListDiff(prevList as ListData, STATUS.DELETED);
2 years ago
}
const diff: ListDiff["diff"] = [];
const prevIndexMatches: number[] = [];
2 years ago
nextList.forEach((nextValue, i) => {
const prevIndex = prevList.findIndex(
(prevValue, prevIdx) =>
isEqual(prevValue, nextValue) && !prevIndexMatches.includes(prevIdx)
2 years ago
);
if (prevIndex > -1) {
prevIndexMatches.push(prevIndex);
}
2 years ago
const indexDiff = prevIndex === -1 ? null : i - prevIndex;
if (indexDiff === 0) {
return diff.push({
value: nextValue,
prevIndex,
newIndex: i,
indexDiff,
status: STATUS.EQUAL,
});
}
if (prevIndex === -1) {
return diff.push({
value: nextValue,
prevIndex: null,
newIndex: i,
indexDiff,
status: STATUS.ADDED,
});
}
return diff.push({
value: nextValue,
prevIndex,
newIndex: i,
indexDiff,
status: STATUS.MOVED,
});
});
prevList.forEach((prevValue, i) => {
if (!prevIndexMatches.includes(i)) {
2 years ago
return diff.splice(i, 0, {
value: prevValue,
prevIndex: i,
newIndex: null,
indexDiff: null,
status: STATUS.DELETED,
});
}
});
return {
type: "list",
status: getListStatus(diff),
2 years ago
diff,
};
};