mirror of
https://github.com/strapi/strapi.git
synced 2025-08-13 19:27:34 +00:00
105 lines
2.0 KiB
TypeScript
105 lines
2.0 KiB
TypeScript
import { isArray, isObject, zip, isEqual, uniq } from 'lodash/fp';
|
|
|
|
const createContext = (): Context => ({ path: [] });
|
|
|
|
export const diff = (a: unknown, b: unknown, ctx: Context = createContext()): Diff[] => {
|
|
const diffs: Diff[] = [];
|
|
const { path } = ctx;
|
|
|
|
const aType = typeof a;
|
|
const bType = typeof b;
|
|
|
|
// Define helpers
|
|
|
|
const added = () => {
|
|
diffs.push({ kind: 'added', path, type: bType, value: b });
|
|
return diffs;
|
|
};
|
|
|
|
const deleted = () => {
|
|
diffs.push({ kind: 'deleted', path, type: aType, value: a });
|
|
return diffs;
|
|
};
|
|
|
|
const modified = () => {
|
|
diffs.push({
|
|
kind: 'modified',
|
|
path,
|
|
types: [aType, bType],
|
|
values: [a, b],
|
|
});
|
|
return diffs;
|
|
};
|
|
|
|
if (aType === 'undefined') {
|
|
return added();
|
|
}
|
|
|
|
if (bType === 'undefined') {
|
|
return deleted();
|
|
}
|
|
|
|
if (isArray(a) && isArray(b)) {
|
|
let k = 0;
|
|
|
|
for (const [aItem, bItem] of zip(a, b)) {
|
|
const kCtx: Context = { path: [...path, k.toString()] };
|
|
const kDiffs = diff(aItem, bItem, kCtx);
|
|
|
|
diffs.push(...kDiffs);
|
|
|
|
k += 1;
|
|
}
|
|
|
|
return diffs;
|
|
}
|
|
|
|
if (isObject(a) && isObject(b)) {
|
|
const keys = uniq(Object.keys(a).concat(Object.keys(b)));
|
|
|
|
for (const key of keys) {
|
|
const aValue = (a as Record<string, unknown>)[key];
|
|
const bValue = (b as Record<string, unknown>)[key];
|
|
|
|
const nestedDiffs = diff(aValue, bValue, { path: [...path, key] });
|
|
|
|
diffs.push(...nestedDiffs);
|
|
}
|
|
|
|
return diffs;
|
|
}
|
|
|
|
if (!isEqual(a, b)) {
|
|
modified();
|
|
}
|
|
|
|
return diffs;
|
|
};
|
|
|
|
export interface AddedDiff<T = unknown> {
|
|
kind: 'added';
|
|
path: string[];
|
|
type: string;
|
|
value: T;
|
|
}
|
|
|
|
export interface ModifiedDiff<T = unknown, P = unknown> {
|
|
kind: 'modified';
|
|
path: string[];
|
|
types: [string, string];
|
|
values: [T, P];
|
|
}
|
|
|
|
export interface DeletedDiff<T = unknown> {
|
|
kind: 'deleted';
|
|
path: string[];
|
|
type: string;
|
|
value: T;
|
|
}
|
|
|
|
export type Diff = AddedDiff | ModifiedDiff | DeletedDiff;
|
|
|
|
export interface Context {
|
|
path: string[];
|
|
}
|