Skip to content

Commit 838429b

Browse files
authored
Merge branch 'master' into support-stream-input
2 parents 5ec6440 + 27306f7 commit 838429b

File tree

2 files changed

+139
-234
lines changed

2 files changed

+139
-234
lines changed

src/lib/object-diff/index.ts

Lines changed: 74 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,19 @@ function getLeanDiff(
1414
showOnly: ObjectDiffOptions["showOnly"] = DEFAULT_OBJECT_DIFF_OPTIONS.showOnly,
1515
): ObjectDiff["diff"] {
1616
const { statuses, granularity } = showOnly;
17-
return diff.reduce(
18-
(acc, value) => {
19-
if (granularity === GRANULARITY.DEEP && value.diff) {
20-
const leanDiff = getLeanDiff(value.diff, showOnly);
21-
if (leanDiff.length > 0) {
22-
return [...acc, { ...value, diff: leanDiff }];
23-
}
17+
const res: ObjectDiff["diff"] = [];
18+
for (let i = 0; i < diff.length; i++) {
19+
const value = diff[i];
20+
if (granularity === GRANULARITY.DEEP && value.diff) {
21+
const leanDiff = getLeanDiff(value.diff, showOnly);
22+
if (leanDiff.length > 0) {
23+
res.push({ ...value, diff: leanDiff });
2424
}
25-
if (statuses.includes(value.status)) {
26-
return [...acc, value];
27-
}
28-
return acc;
29-
},
30-
[] as ObjectDiff["diff"],
31-
);
25+
} else if (statuses.includes(value.status)) {
26+
res.push(value);
27+
}
28+
}
29+
return res;
3230
}
3331

3432
function getObjectStatus(diff: ObjectDiff["diff"]): OBJECT_STATUS {
@@ -50,34 +48,37 @@ function formatSingleObjectDiff(
5048
};
5149
}
5250
const diff: ObjectDiff["diff"] = [];
53-
Object.entries(data).forEach(([property, value]) => {
51+
52+
for (const [property, value] of Object.entries(data)) {
5453
if (isObject(value)) {
5554
const subPropertiesDiff: Diff[] = [];
56-
Object.entries(value).forEach(([subProperty, subValue]) => {
55+
for (const [subProperty, subValue] of Object.entries(value)) {
5756
subPropertiesDiff.push({
5857
property: subProperty,
5958
previousValue: status === OBJECT_STATUS.ADDED ? undefined : subValue,
6059
currentValue: status === OBJECT_STATUS.ADDED ? subValue : undefined,
6160
status,
6261
});
63-
});
64-
return diff.push({
62+
}
63+
diff.push({
6564
property,
6665
previousValue:
6766
status === OBJECT_STATUS.ADDED ? undefined : data[property],
6867
currentValue: status === OBJECT_STATUS.ADDED ? value : undefined,
6968
status,
7069
diff: subPropertiesDiff,
7170
});
71+
} else {
72+
diff.push({
73+
property,
74+
previousValue:
75+
status === OBJECT_STATUS.ADDED ? undefined : data[property],
76+
currentValue: status === OBJECT_STATUS.ADDED ? value : undefined,
77+
status,
78+
});
7279
}
73-
return diff.push({
74-
property,
75-
previousValue:
76-
status === OBJECT_STATUS.ADDED ? undefined : data[property],
77-
currentValue: status === OBJECT_STATUS.ADDED ? value : undefined,
78-
status,
79-
});
80-
});
80+
}
81+
8182
if (options.showOnly && options.showOnly.statuses.length > 0) {
8283
return {
8384
type: "object",
@@ -92,20 +93,6 @@ function formatSingleObjectDiff(
9293
};
9394
}
9495

95-
function getPreviousMatch(
96-
previousValue: unknown | undefined,
97-
nextSubProperty: unknown,
98-
options?: ObjectDiffOptions,
99-
): unknown | undefined {
100-
if (!previousValue) {
101-
return undefined;
102-
}
103-
const previousMatch = Object.entries(previousValue).find(([subPreviousKey]) =>
104-
isEqual(subPreviousKey, nextSubProperty, options),
105-
);
106-
return previousMatch ? previousMatch[1] : undefined;
107-
}
108-
10996
function getValueStatus(
11097
previousValue: unknown,
11198
nextValue: unknown,
@@ -117,92 +104,61 @@ function getValueStatus(
117104
return OBJECT_STATUS.UPDATED;
118105
}
119106

120-
function getPropertyStatus(subPropertiesDiff: Diff[]): OBJECT_STATUS {
121-
return subPropertiesDiff.some(
122-
(property) => property.status !== OBJECT_STATUS.EQUAL,
123-
)
124-
? OBJECT_STATUS.UPDATED
125-
: OBJECT_STATUS.EQUAL;
126-
}
127-
128-
function getDeletedProperties(
129-
previousValue: Record<string, unknown> | undefined,
130-
nextValue: Record<string, unknown>,
131-
): { property: string; value: unknown }[] | undefined {
132-
if (!previousValue) return undefined;
133-
const prevKeys = Object.keys(previousValue);
134-
const nextKeys = Object.keys(nextValue);
135-
const deletedKeys = prevKeys.filter((prevKey) => !nextKeys.includes(prevKey));
136-
if (deletedKeys.length > 0) {
137-
return deletedKeys.map((deletedKey) => ({
138-
property: deletedKey,
139-
value: previousValue[deletedKey],
140-
}));
141-
}
142-
return undefined;
143-
}
144-
145-
function getSubPropertiesDiff(
146-
previousValue: Record<string, unknown> | undefined,
107+
function getDiff(
108+
previousValue: Record<string, unknown> | undefined = {},
147109
nextValue: Record<string, unknown>,
148110
options?: ObjectDiffOptions,
149111
): Diff[] {
150-
const subPropertiesDiff: Diff[] = [];
151-
let subDiff: Diff[];
152-
const deletedMainSubProperties = getDeletedProperties(
153-
previousValue,
154-
nextValue,
155-
);
156-
if (deletedMainSubProperties) {
157-
deletedMainSubProperties.forEach((deletedProperty) => {
158-
subPropertiesDiff.push({
159-
property: deletedProperty.property,
160-
previousValue: deletedProperty.value,
112+
const diff: Diff[] = [];
113+
const allKeys = new Set([
114+
...Object.keys(previousValue),
115+
...Object.keys(nextValue),
116+
]);
117+
118+
for (const property of allKeys) {
119+
const prevSubValue = previousValue[property];
120+
const nextSubValue = nextValue[property];
121+
if (!(property in nextValue)) {
122+
diff.push({
123+
property,
124+
previousValue: prevSubValue,
161125
currentValue: undefined,
162126
status: OBJECT_STATUS.DELETED,
163127
});
164-
});
165-
}
166-
Object.entries(nextValue).forEach(([nextSubProperty, nextSubValue]) => {
167-
const previousMatch = getPreviousMatch(
168-
previousValue,
169-
nextSubProperty,
170-
options,
171-
);
172-
if (!previousMatch) {
173-
return subPropertiesDiff.push({
174-
property: nextSubProperty,
175-
previousValue: previousMatch,
128+
continue;
129+
}
130+
if (!(property in previousValue)) {
131+
diff.push({
132+
property,
133+
previousValue: undefined,
176134
currentValue: nextSubValue,
177-
status:
178-
!previousValue || !(nextSubProperty in previousValue)
179-
? OBJECT_STATUS.ADDED
180-
: previousMatch === nextSubValue
181-
? OBJECT_STATUS.EQUAL
182-
: OBJECT_STATUS.UPDATED,
135+
status: OBJECT_STATUS.ADDED,
183136
});
137+
continue;
184138
}
185-
if (isObject(nextSubValue)) {
186-
const data: Diff[] = getSubPropertiesDiff(
187-
previousMatch as Record<string, unknown>,
188-
nextSubValue,
189-
options,
139+
if (isObject(nextSubValue) && isObject(prevSubValue)) {
140+
const subDiff = getDiff(prevSubValue, nextSubValue, options);
141+
const isUpdated = subDiff.some(
142+
(entry) => entry.status !== OBJECT_STATUS.EQUAL,
190143
);
191-
if (data && data.length > 0) {
192-
subDiff = data;
193-
}
194-
}
195-
if (previousMatch) {
196-
subPropertiesDiff.push({
197-
property: nextSubProperty,
198-
previousValue: previousMatch,
144+
diff.push({
145+
property,
146+
previousValue: prevSubValue,
147+
currentValue: nextSubValue,
148+
status: isUpdated ? OBJECT_STATUS.UPDATED : OBJECT_STATUS.EQUAL,
149+
...(isUpdated && { diff: subDiff }),
150+
});
151+
} else {
152+
const status = getValueStatus(prevSubValue, nextSubValue, options);
153+
diff.push({
154+
property,
155+
previousValue: prevSubValue,
199156
currentValue: nextSubValue,
200-
status: getValueStatus(previousMatch, nextSubValue, options),
201-
...(!!subDiff && { diff: subDiff }),
157+
status,
202158
});
203159
}
204-
});
205-
return subPropertiesDiff;
160+
}
161+
return diff;
206162
}
207163

208164
/**
@@ -234,66 +190,12 @@ export function getObjectDiff(
234190
if (!nextData) {
235191
return formatSingleObjectDiff(prevData, OBJECT_STATUS.DELETED, options);
236192
}
237-
const diff: ObjectDiff["diff"] = [];
238-
Object.entries(nextData).forEach(([nextProperty, nextValue]) => {
239-
const previousValue = prevData[nextProperty];
240-
if (!previousValue) {
241-
return diff.push({
242-
property: nextProperty,
243-
previousValue,
244-
currentValue: nextValue,
245-
status: !(nextProperty in prevData)
246-
? OBJECT_STATUS.ADDED
247-
: previousValue === nextValue
248-
? OBJECT_STATUS.EQUAL
249-
: OBJECT_STATUS.UPDATED,
250-
});
251-
}
252-
if (isObject(nextValue)) {
253-
const subPropertiesDiff: Diff[] = getSubPropertiesDiff(
254-
previousValue as Record<string, unknown>,
255-
nextValue,
256-
options,
257-
);
258-
const subPropertyStatus = getPropertyStatus(subPropertiesDiff);
259-
return diff.push({
260-
property: nextProperty,
261-
previousValue,
262-
currentValue: nextValue,
263-
status: subPropertyStatus,
264-
...(subPropertyStatus !== OBJECT_STATUS.EQUAL && {
265-
diff: subPropertiesDiff,
266-
}),
267-
});
268-
}
269-
return diff.push({
270-
property: nextProperty,
271-
previousValue,
272-
currentValue: nextValue,
273-
status: getValueStatus(previousValue, nextValue, options),
274-
});
275-
});
276-
const deletedProperties = getDeletedProperties(prevData, nextData);
277-
if (deletedProperties) {
278-
deletedProperties.forEach((deletedProperty) => {
279-
diff.push({
280-
property: deletedProperty.property,
281-
previousValue: deletedProperty.value,
282-
currentValue: undefined,
283-
status: OBJECT_STATUS.DELETED,
284-
});
285-
});
286-
}
287-
if (options.showOnly && options.showOnly.statuses.length > 0) {
288-
return {
289-
type: "object",
290-
status: getObjectStatus(diff),
291-
diff: getLeanDiff(diff, options.showOnly),
292-
};
293-
}
193+
const diff: ObjectDiff["diff"] = getDiff(prevData, nextData, options);
194+
const status = getObjectStatus(diff);
195+
const showLeanDiff = (options?.showOnly?.statuses?.length || 0) > 0;
294196
return {
295197
type: "object",
296-
status: getObjectStatus(diff),
297-
diff,
198+
status,
199+
diff: showLeanDiff ? getLeanDiff(diff, options.showOnly) : diff,
298200
};
299201
}

0 commit comments

Comments
 (0)