@rimbu/deep 0.9.2 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/main/index.js +12 -3
- package/dist/main/index.js.map +1 -1
- package/dist/main/internal.js +2 -4
- package/dist/main/internal.js.map +1 -1
- package/dist/main/match.js +197 -132
- package/dist/main/match.js.map +1 -1
- package/dist/main/patch.js +125 -106
- package/dist/main/patch.js.map +1 -1
- package/dist/main/path.js +14 -39
- package/dist/main/path.js.map +1 -1
- package/dist/main/protected.js +22 -0
- package/dist/main/protected.js.map +1 -0
- package/dist/module/index.js +3 -2
- package/dist/module/index.js.map +1 -1
- package/dist/module/internal.js +2 -4
- package/dist/module/internal.js.map +1 -1
- package/dist/module/match.js +180 -97
- package/dist/module/match.js.map +1 -1
- package/dist/module/patch.js +113 -87
- package/dist/module/patch.js.map +1 -1
- package/dist/module/path.js +15 -36
- package/dist/module/path.js.map +1 -1
- package/dist/module/protected.js +18 -0
- package/dist/module/protected.js.map +1 -0
- package/dist/types/index.d.ts +3 -2
- package/dist/types/internal.d.ts +2 -4
- package/dist/types/match.d.ts +93 -80
- package/dist/types/patch.d.ts +64 -61
- package/dist/types/path.d.ts +9 -20
- package/dist/types/protected.d.ts +32 -0
- package/package.json +4 -4
- package/src/index.ts +12 -2
- package/src/internal.ts +3 -4
- package/src/match.ts +254 -163
- package/src/patch.ts +204 -147
- package/src/path.ts +20 -44
- package/src/protected.ts +44 -0
- package/dist/main/immutable.js +0 -12
- package/dist/main/immutable.js.map +0 -1
- package/dist/main/literal.js +0 -41
- package/dist/main/literal.js.map +0 -1
- package/dist/module/immutable.js +0 -8
- package/dist/module/immutable.js.map +0 -1
- package/dist/module/literal.js +0 -37
- package/dist/module/literal.js.map +0 -1
- package/dist/types/immutable.d.ts +0 -13
- package/dist/types/literal.d.ts +0 -48
- package/src/immutable.ts +0 -21
- package/src/literal.ts +0 -70
package/dist/module/match.js
CHANGED
|
@@ -1,139 +1,222 @@
|
|
|
1
|
-
import { RimbuError } from '@rimbu/base';
|
|
2
|
-
import { Literal } from './internal';
|
|
1
|
+
import { RimbuError, isPlainObj, isIterable, } from '@rimbu/base';
|
|
3
2
|
export var Match;
|
|
4
3
|
(function (Match) {
|
|
5
4
|
/**
|
|
6
|
-
* Returns true if
|
|
7
|
-
* @typeparam T - the type of
|
|
8
|
-
* @
|
|
9
|
-
* @
|
|
5
|
+
* Returns a matcher that returns true if every given `matchItem` matches the given value.
|
|
6
|
+
* @typeparam T - the type of value to match
|
|
7
|
+
* @typeparam R - the root object type
|
|
8
|
+
* @typeparam Q - a utility type for the matcher
|
|
9
|
+
* @param matchItems - the match specifications to test
|
|
10
10
|
* @example
|
|
11
11
|
* ```ts
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* const input = { a: 1, b: { c: true, d: 'a' } }
|
|
13
|
+
* match(input, Match.every({ a: 1, { c: true } } )) // => true
|
|
14
|
+
* match(input, Match.every({ a: 1, { c: false } } )) // => false
|
|
14
15
|
* ```
|
|
15
16
|
*/
|
|
16
|
-
function
|
|
17
|
-
return (
|
|
18
|
-
for (const matcher of matchers) {
|
|
19
|
-
if (!matchSingle(value, matcher, value, value)) {
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return true;
|
|
24
|
-
};
|
|
17
|
+
function every(...matchItems) {
|
|
18
|
+
return new Every(matchItems);
|
|
25
19
|
}
|
|
26
|
-
Match.
|
|
20
|
+
Match.every = every;
|
|
27
21
|
/**
|
|
28
|
-
* Returns true if
|
|
29
|
-
* @typeparam T - the type of
|
|
30
|
-
* @
|
|
31
|
-
* @
|
|
22
|
+
* Returns a matcher that returns true if at least one of given `matchItem` matches the given value.
|
|
23
|
+
* @typeparam T - the type of value to match
|
|
24
|
+
* @typeparam R - the root object type
|
|
25
|
+
* @typeparam Q - a utility type for the matcher
|
|
26
|
+
* @param matchItems - the match specifications to test
|
|
32
27
|
* @example
|
|
33
28
|
* ```ts
|
|
34
|
-
*
|
|
35
|
-
*
|
|
29
|
+
* const input = { a: 1, b: { c: true, d: 'a' } }
|
|
30
|
+
* match(input, Match.some({ a: 5, { c: true } } )) // => true
|
|
31
|
+
* match(input, Match.some({ a: 5, { c: false } } )) // => false
|
|
36
32
|
* ```
|
|
37
33
|
*/
|
|
38
|
-
function
|
|
39
|
-
return (
|
|
40
|
-
for (const matcher of matchers) {
|
|
41
|
-
if (matchSingle(value, matcher, value, value)) {
|
|
42
|
-
return true;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return false;
|
|
46
|
-
};
|
|
34
|
+
function some(...matchItems) {
|
|
35
|
+
return new Some(matchItems);
|
|
47
36
|
}
|
|
48
|
-
Match.
|
|
37
|
+
Match.some = some;
|
|
49
38
|
/**
|
|
50
|
-
* Returns a
|
|
51
|
-
*
|
|
52
|
-
* @typeparam
|
|
53
|
-
* @typeparam
|
|
54
|
-
* @param
|
|
39
|
+
* Returns a matcher that returns true if none of given `matchItem` matches the given value.
|
|
40
|
+
* @typeparam T - the type of value to match
|
|
41
|
+
* @typeparam R - the root object type
|
|
42
|
+
* @typeparam Q - a utility type for the matcher
|
|
43
|
+
* @param matchItems - the match specifications to test
|
|
55
44
|
* @example
|
|
56
45
|
* ```ts
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* console.log(m({ name: 'abc', age: 10 }))
|
|
61
|
-
* // => false
|
|
62
|
-
* console.log(m({ name: 'abc', age: 20 }))
|
|
63
|
-
* // => true
|
|
64
|
-
* console.log(m({ name: 'a', age: 20 }))
|
|
65
|
-
* // => false
|
|
46
|
+
* const input = { a: 1, b: { c: true, d: 'a' } }
|
|
47
|
+
* match(input, Match.none({ a: 5, { c: true } } )) // => false
|
|
48
|
+
* match(input, Match.none({ a: 5, { c: false } } )) // => true
|
|
66
49
|
* ```
|
|
67
50
|
*/
|
|
68
|
-
function
|
|
69
|
-
return
|
|
51
|
+
function none(...matchItems) {
|
|
52
|
+
return new None(matchItems);
|
|
70
53
|
}
|
|
71
|
-
Match.
|
|
54
|
+
Match.none = none;
|
|
72
55
|
/**
|
|
73
|
-
* Returns a
|
|
74
|
-
*
|
|
75
|
-
* @typeparam
|
|
76
|
-
* @typeparam
|
|
77
|
-
* @param
|
|
56
|
+
* Returns a matcher that returns true if exactly one of given `matchItem` matches the given value.
|
|
57
|
+
* @typeparam T - the type of value to match
|
|
58
|
+
* @typeparam R - the root object type
|
|
59
|
+
* @typeparam Q - a utility type for the matcher
|
|
60
|
+
* @param matchItems - the match specifications to test
|
|
78
61
|
* @example
|
|
79
62
|
* ```ts
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* console.log(m({ name: 'abc', age: 10 }))
|
|
84
|
-
* // => true
|
|
85
|
-
* console.log(m({ name: 'abc', age: 20 }))
|
|
86
|
-
* // => true
|
|
87
|
-
* console.log(m({ name: 'a', age: 20 }))
|
|
88
|
-
* // => true
|
|
89
|
-
* console.log(m({ name: 'a', age: 10 }))
|
|
90
|
-
* // => false
|
|
63
|
+
* const input = { a: 1, b: { c: true, d: 'a' } }
|
|
64
|
+
* match(input, Match.single({ a: 1, { c: true } } )) // => false
|
|
65
|
+
* match(input, Match.single({ a: 1, { c: false } } )) // => true
|
|
91
66
|
* ```
|
|
92
67
|
*/
|
|
93
|
-
function
|
|
94
|
-
return
|
|
68
|
+
function single(...matchItems) {
|
|
69
|
+
return new Single(matchItems);
|
|
95
70
|
}
|
|
96
|
-
Match.
|
|
71
|
+
Match.single = single;
|
|
97
72
|
})(Match || (Match = {}));
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
73
|
+
class Every {
|
|
74
|
+
constructor(matchItems) {
|
|
75
|
+
this.matchItems = matchItems;
|
|
101
76
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
77
|
+
}
|
|
78
|
+
class Some {
|
|
79
|
+
constructor(matchItems) {
|
|
80
|
+
this.matchItems = matchItems;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
class None {
|
|
84
|
+
constructor(matchItems) {
|
|
85
|
+
this.matchItems = matchItems;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
class Single {
|
|
89
|
+
constructor(matchItems) {
|
|
90
|
+
this.matchItems = matchItems;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Returns true if the given `value` object matches the given `matcher`, false otherwise.
|
|
95
|
+
* @typeparam T - the input value type
|
|
96
|
+
* @param value - the value to match (should be a plain object)
|
|
97
|
+
* @param matcher - a matcher object or a function taking the matcher API and returning a match object
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* const input = { a: 1, b: { c: true, d: 'a' } }
|
|
101
|
+
* match(input, { a: 1 }) // => true
|
|
102
|
+
* match(input, { a: 2 }) // => false
|
|
103
|
+
* match(input, { a: v => v > 10 }) // => false
|
|
104
|
+
* match(input, { b: { c: true }}) // => true
|
|
105
|
+
* match(input, ({ every }) => every({ a: v => v > 0 }, { b: { c: true } } )) // => true
|
|
106
|
+
* match(input, { b: { c: (v, parent, root) => v && parent.d.length > 0 && root.a > 0 } })
|
|
107
|
+
* // => true
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
export function match(value, matcher) {
|
|
111
|
+
if (matcher instanceof Function) {
|
|
112
|
+
return matchOptions(value, value, matcher(Match));
|
|
113
|
+
}
|
|
114
|
+
return matchOptions(value, value, matcher);
|
|
115
|
+
}
|
|
116
|
+
function matchOptions(value, root, matcher) {
|
|
117
|
+
if (matcher instanceof Every) {
|
|
118
|
+
let i = -1;
|
|
119
|
+
const { matchItems } = matcher;
|
|
120
|
+
const len = matchItems.length;
|
|
121
|
+
while (++i < len) {
|
|
122
|
+
if (!matchOptions(value, root, matchItems[i])) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
105
125
|
}
|
|
106
|
-
|
|
107
|
-
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
if (matcher instanceof Some) {
|
|
129
|
+
let i = -1;
|
|
130
|
+
const { matchItems } = matcher;
|
|
131
|
+
const len = matchItems.length;
|
|
132
|
+
while (++i < len) {
|
|
133
|
+
if (matchOptions(value, root, matchItems[i])) {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
108
136
|
}
|
|
109
|
-
return
|
|
137
|
+
return false;
|
|
110
138
|
}
|
|
111
|
-
if (
|
|
112
|
-
|
|
139
|
+
if (matcher instanceof None) {
|
|
140
|
+
let i = -1;
|
|
141
|
+
const { matchItems } = matcher;
|
|
142
|
+
const len = matchItems.length;
|
|
143
|
+
while (++i < len) {
|
|
144
|
+
if (matchOptions(value, root, matchItems[i])) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return true;
|
|
113
149
|
}
|
|
114
|
-
if (
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
150
|
+
if (matcher instanceof Single) {
|
|
151
|
+
let i = -1;
|
|
152
|
+
const { matchItems } = matcher;
|
|
153
|
+
const len = matchItems.length;
|
|
154
|
+
let matched = false;
|
|
155
|
+
while (++i < len) {
|
|
156
|
+
if (matchOptions(value, root, matchItems[i])) {
|
|
157
|
+
if (matched) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
matched = true;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return matched;
|
|
120
164
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
165
|
+
if (isPlainObj(matcher)) {
|
|
166
|
+
return matchRecord(value, root, matcher);
|
|
167
|
+
}
|
|
168
|
+
return Object.is(value, matcher);
|
|
169
|
+
}
|
|
170
|
+
function matchRecord(value, root, matcher) {
|
|
171
|
+
if (!isPlainObj(matcher)) {
|
|
172
|
+
RimbuError.throwInvalidUsageError('match: to prevent accidental errors, match only supports plain objects as input.');
|
|
125
173
|
}
|
|
126
174
|
for (const key in matcher) {
|
|
127
175
|
if (!(key in value))
|
|
128
176
|
return false;
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
177
|
+
const matchValue = matcher[key];
|
|
178
|
+
const target = value[key];
|
|
179
|
+
if (matchValue instanceof Function) {
|
|
180
|
+
if (target instanceof Function && Object.is(target, matchValue)) {
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
const result = matchValue(target, value, root);
|
|
184
|
+
if (typeof result === 'boolean') {
|
|
185
|
+
if (result) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
if (!matchRecordItem(target, root, result)) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
if (!matchRecordItem(target, root, matchValue)) {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
132
198
|
}
|
|
133
|
-
const result = matchSingle(value[key], matchKey, value, root);
|
|
134
|
-
if (!result)
|
|
135
|
-
return false;
|
|
136
199
|
}
|
|
137
200
|
return true;
|
|
138
201
|
}
|
|
202
|
+
function matchRecordItem(value, root, matcher) {
|
|
203
|
+
if (isIterable(matcher) && isIterable(value)) {
|
|
204
|
+
const it1 = value[Symbol.iterator]();
|
|
205
|
+
const it2 = matcher[Symbol.iterator]();
|
|
206
|
+
while (true) {
|
|
207
|
+
const v1 = it1.next();
|
|
208
|
+
const v2 = it2.next();
|
|
209
|
+
if (v1.done !== v2.done || v1.value !== v2.value) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
if (v1.done) {
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (isPlainObj(value)) {
|
|
218
|
+
return matchOptions(value, root, matcher);
|
|
219
|
+
}
|
|
220
|
+
return Object.is(value, matcher);
|
|
221
|
+
}
|
|
139
222
|
//# sourceMappingURL=match.js.map
|
package/dist/module/match.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"match.js","sourceRoot":"","sources":["../../src/match.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"match.js","sourceRoot":"","sources":["../../src/match.ts"],"names":[],"mappings":"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"}
|
package/dist/module/patch.js
CHANGED
|
@@ -1,110 +1,136 @@
|
|
|
1
|
-
import { RimbuError } from '@rimbu/base';
|
|
2
|
-
import { Literal } from './internal';
|
|
3
|
-
/**
|
|
4
|
-
* Returns an updated version of given `value`, without modifying the value, where the contents
|
|
5
|
-
* are updated according to the given `patches` Patch array.
|
|
6
|
-
* @typeparam T - the type of the value to patch
|
|
7
|
-
* @param value - the value to update
|
|
8
|
-
* @param patches - one or more `Patch` objects indicating modifications to the value
|
|
9
|
-
* @example
|
|
10
|
-
* ```ts
|
|
11
|
-
* patch({ g: { h: 5 }})({ g: { h: 6 }}) // => { g: { h: 6 }}
|
|
12
|
-
* patch({ g: { h: 5 }})({ g: { h: v => v + 1 }}) // => { g: { h: 6 }}
|
|
13
|
-
* patch({ g: { h: 5 }})({ g: { h: 1 }}, { g: { h: v => v + 1 }})
|
|
14
|
-
* // => { g: { h: 2 }}
|
|
15
|
-
* patch({ a: 1, b: 3 })({ a: (v, p) => v * p.b, (v, p) => v + p.a })
|
|
16
|
-
* // => { a: 3, b: 4 }
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
|
-
export function patch(value) {
|
|
20
|
-
return function (...patches) {
|
|
21
|
-
let result = value;
|
|
22
|
-
for (const p of patches) {
|
|
23
|
-
result = patchSingle(result, p, result, result);
|
|
24
|
-
}
|
|
25
|
-
return result;
|
|
26
|
-
};
|
|
27
|
-
}
|
|
1
|
+
import { RimbuError, isPlainObj, } from '@rimbu/base';
|
|
28
2
|
export var Patch;
|
|
29
3
|
(function (Patch) {
|
|
30
|
-
Patch.MAP = Symbol('Patch.ALL');
|
|
31
4
|
/**
|
|
32
|
-
* Returns a function that patches a given
|
|
33
|
-
*
|
|
34
|
-
* @typeparam
|
|
35
|
-
* @
|
|
36
|
-
* @param patches - the patches to apply to a given object
|
|
5
|
+
* Returns a function that patches a given `value` with the given `patchItems`.
|
|
6
|
+
* @typeparam T - the patch value type
|
|
7
|
+
* @typeparam Q - the input value type
|
|
8
|
+
* @param patchItems - a number of `Patch` objects that patch a given value of type T.
|
|
37
9
|
* @example
|
|
38
10
|
* ```ts
|
|
39
|
-
* const
|
|
40
|
-
*
|
|
41
|
-
* // => { a:
|
|
11
|
+
* const items = [{ a: 1, b: 'a' }, { a: 2, b: 'b' }]
|
|
12
|
+
* items.map(Patch.create({ a: v => v + 1 }))
|
|
13
|
+
* // => [{ a: 2, b: 'a' }, { a: 3, b: 'b' }]
|
|
42
14
|
* ```
|
|
43
15
|
*/
|
|
44
|
-
function create(...
|
|
45
|
-
return (value) => patch(value
|
|
16
|
+
function create(...patchItems) {
|
|
17
|
+
return (value) => patch(value, ...patchItems);
|
|
46
18
|
}
|
|
47
19
|
Patch.create = create;
|
|
48
20
|
})(Patch || (Patch = {}));
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
21
|
+
class NestedObj {
|
|
22
|
+
constructor(patchDataItems) {
|
|
23
|
+
this.patchDataItems = patchDataItems;
|
|
52
24
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Returns a nested patch object based on the given `patchDataItems` that work on a subpart
|
|
28
|
+
* of a larger object to be patched.
|
|
29
|
+
* @typeparam T - the input value type
|
|
30
|
+
* @typeparam R - the root object type
|
|
31
|
+
* @typeparam Q - the patch type
|
|
32
|
+
* @param patchDataItems - a number of `Patch` objects to be applied to the subpart of the object
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* patch({ a: 1, b: { c: true, d: 'a' } }, { b: patchNested({ d: 'b' }) })
|
|
36
|
+
* // => { a: 1, b: { c: true, d: 'b' } }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export function patchNested(...patchDataItems) {
|
|
40
|
+
return new NestedObj(patchDataItems);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Returns an immutably updated version of the given `value` where the given `patchItems` have been
|
|
44
|
+
* applied to the result.
|
|
45
|
+
* @param value - the input value to patch
|
|
46
|
+
* @param patchItems - the `Patch` objects to apply to the input value
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* const input = { a: 1, b: { c: true, d: 'a' } }
|
|
50
|
+
* patch(input, { a: 2 }) // => { a: 2, b: { c: true, d: 'a' } }
|
|
51
|
+
* patch(input: ($) => ({ b: $({ c: v => !v }) }) )
|
|
52
|
+
* // => { a: 1, b: { c: false, d: 'a' } }
|
|
53
|
+
* patch(input: ($) => ({ a: v => v + 1, b: $({ d: 'q' }) }) )
|
|
54
|
+
* // => { a: 2, b: { c: true, d: 'q' } }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export function patch(value, ...patchItems) {
|
|
58
|
+
const newValue = isPlainObj(value) ? Object.assign({}, value) : value;
|
|
59
|
+
const changedRef = { changed: false };
|
|
60
|
+
const result = processPatch(newValue, newValue, patchItems, changedRef);
|
|
61
|
+
if (changedRef.changed)
|
|
62
|
+
return result;
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
65
|
+
function processPatch(value, root, patchDataItems, changedRef) {
|
|
66
|
+
let i = -1;
|
|
67
|
+
const len = patchDataItems.length;
|
|
68
|
+
while (++i < len) {
|
|
69
|
+
const patchItem = patchDataItems[i];
|
|
70
|
+
if (patchItem instanceof Function) {
|
|
71
|
+
const item = patchItem(patchNested);
|
|
72
|
+
if (item instanceof NestedObj) {
|
|
73
|
+
processPatch(value, root, item.patchDataItems, changedRef);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
processPatchObj(value, root, item, changedRef);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
processPatchObj(value, root, patchItem, changedRef);
|
|
58
81
|
}
|
|
82
|
+
}
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
function processPatchObj(value, root, patchData, changedRef) {
|
|
86
|
+
if (undefined === value || null === value) {
|
|
59
87
|
return value;
|
|
60
88
|
}
|
|
61
|
-
if (
|
|
62
|
-
RimbuError.
|
|
89
|
+
if (!isPlainObj(patchData)) {
|
|
90
|
+
RimbuError.throwInvalidUsageError('patch: received patch object should be a plain object');
|
|
63
91
|
}
|
|
64
|
-
if (
|
|
65
|
-
|
|
66
|
-
if (null === patcher)
|
|
67
|
-
return null;
|
|
68
|
-
if (Literal.isLiteral(patcher)) {
|
|
69
|
-
return Literal.getValue(patcher);
|
|
92
|
+
if (!isPlainObj(value)) {
|
|
93
|
+
RimbuError.throwInvalidUsageError('patch: received source object should be a plain object');
|
|
70
94
|
}
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
let result = undefined;
|
|
78
|
-
for (let i = 0; i < arr.length; i++) {
|
|
79
|
-
const currentItem = arr[i];
|
|
80
|
-
const newItem = patchSingle(currentItem, itemPatch, value, root);
|
|
81
|
-
if (!Object.is(newItem, currentItem)) {
|
|
82
|
-
if (undefined === result) {
|
|
83
|
-
result = arr.slice();
|
|
84
|
-
}
|
|
85
|
-
result[i] = newItem;
|
|
86
|
-
}
|
|
95
|
+
for (const key in patchData) {
|
|
96
|
+
const target = value[key];
|
|
97
|
+
// prevent prototype pollution
|
|
98
|
+
if (key === '__proto__' ||
|
|
99
|
+
(key === 'constructor' && target instanceof Function)) {
|
|
100
|
+
RimbuError.throwInvalidUsageError(`patch: received patch object key '${key}' which is not allowed to prevent prototype pollution`);
|
|
87
101
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
102
|
+
const update = patchData[key];
|
|
103
|
+
if (!(key in value) && update instanceof Function) {
|
|
104
|
+
RimbuError.throwInvalidUsageError(`patch: received update function object key ${key} but the key was not present in the source object. Either explicitely set the value in the source to undefined or use a direct value.`);
|
|
105
|
+
}
|
|
106
|
+
if (undefined === update) {
|
|
107
|
+
RimbuError.throwInvalidUsageError("patch: received 'undefined' as patch value. Due to type system issues we cannot prevent this through typing, but please use '() => undefined' or '() => yourVar' instead. This value will be ignored for safety.");
|
|
108
|
+
}
|
|
109
|
+
let newValue;
|
|
110
|
+
if (update instanceof Function) {
|
|
111
|
+
newValue = processPatchObjItem(target, root, update(target, value, root), changedRef);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
newValue = processPatchObjItem(target, root, update, changedRef);
|
|
99
115
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
changed = true;
|
|
103
|
-
clone[key] = newValue;
|
|
116
|
+
if (!Object.is(newValue, target)) {
|
|
117
|
+
value[key] = newValue;
|
|
118
|
+
changedRef.changed = true;
|
|
104
119
|
}
|
|
105
120
|
}
|
|
106
|
-
if (changed)
|
|
107
|
-
return clone;
|
|
108
121
|
return value;
|
|
109
122
|
}
|
|
123
|
+
function processPatchObjItem(value, root, patchResult, superChangedRef) {
|
|
124
|
+
if (patchResult instanceof NestedObj) {
|
|
125
|
+
const newValue = isPlainObj(value) ? Object.assign({}, value) : value;
|
|
126
|
+
const changedRef = { changed: false };
|
|
127
|
+
const result = processPatch(newValue, root, patchResult.patchDataItems, changedRef);
|
|
128
|
+
if (changedRef.changed) {
|
|
129
|
+
superChangedRef.changed = true;
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
return value;
|
|
133
|
+
}
|
|
134
|
+
return patchResult;
|
|
135
|
+
}
|
|
110
136
|
//# sourceMappingURL=patch.js.map
|
package/dist/module/patch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patch.js","sourceRoot":"","sources":["../../src/patch.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"patch.js","sourceRoot":"","sources":["../../src/patch.ts"],"names":[],"mappings":"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"}
|