-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathpatch.ts
More file actions
71 lines (65 loc) · 2.29 KB
/
patch.ts
File metadata and controls
71 lines (65 loc) · 2.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import { isDictLike } from "https://lib.deno.dev/x/is_like@latest/index.js";
import { isValid } from "https://lib.deno.dev/x/ayonli_jsext@latest/object/index.ts";
import isEmpty from "./isEmpty.ts";
/**
* Patches the differences onto the `origin` object from the `input` object. If
* a property exists in both objects and the values are not equal, the `input`
* one will be taken. However, those properties that are only presents in the
* `origin` object will remain untouched.
*
* NOTE: This function mutates the `origin` object and returns the patched
* differences, when patching, any void value in the `input` object will be
* ignored.
*
* This function is very useful, for example, a client issued a patch of the
* resource and the server wants to know what properties has been modified by
* this update so that it can perform some extra operations to provide a better
* user experience.
*/
export default function patch<T, U>(
origin: T,
input: U,
deep = false,
ignoreEmptyStrings = false,
): T & Partial<U> {
return doPatch(origin, input, deep, ignoreEmptyStrings, false);
}
function doPatch(
origin: any,
input: any,
deep: boolean,
ignoreEmptyStrings: boolean,
isChildNode: boolean
) {
if (isDictLike(origin) && isDictLike(input)) {
let keys = Reflect.ownKeys(input);
let result: any = {};
keys.forEach(key => {
if (origin[key] !== input[key] &&
isValid(input[key]) && // ignore invalid values
(!ignoreEmptyStrings || input[key] !== "")
) {
if (deep && isDictLike(origin[key]) && isDictLike(input[key])) {
let _result = doPatch(
origin[key],
input[key],
deep,
ignoreEmptyStrings,
true
);
if (!isEmpty(_result)) {
result[key] = _result;
Object.assign(origin[key], input[key]);
}
} else {
result[key] = origin[key] = input[key];
}
}
});
return result;
} else if (isChildNode) {
return input;
} else {
return {};
}
}