@rimbu/deep 0.11.3 → 0.12.1

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.
Files changed (53) hide show
  1. package/dist/main/deep.js +211 -0
  2. package/dist/main/deep.js.map +1 -0
  3. package/dist/main/index.js +7 -9
  4. package/dist/main/index.js.map +1 -1
  5. package/dist/main/internal.js +6 -4
  6. package/dist/main/internal.js.map +1 -1
  7. package/dist/main/match.js +160 -199
  8. package/dist/main/match.js.map +1 -1
  9. package/dist/main/patch.js +101 -125
  10. package/dist/main/patch.js.map +1 -1
  11. package/dist/main/path.js +109 -62
  12. package/dist/main/path.js.map +1 -1
  13. package/dist/main/protected.js +0 -19
  14. package/dist/main/protected.js.map +1 -1
  15. package/dist/main/selector.js +40 -0
  16. package/dist/main/selector.js.map +1 -0
  17. package/dist/main/tuple.js.map +1 -1
  18. package/dist/module/deep.js +192 -0
  19. package/dist/module/deep.js.map +1 -0
  20. package/dist/module/index.js +9 -1
  21. package/dist/module/index.js.map +1 -1
  22. package/dist/module/internal.js +4 -4
  23. package/dist/module/internal.js.map +1 -1
  24. package/dist/module/match.js +159 -179
  25. package/dist/module/match.js.map +1 -1
  26. package/dist/module/patch.js +91 -112
  27. package/dist/module/patch.js.map +1 -1
  28. package/dist/module/path.js +99 -44
  29. package/dist/module/path.js.map +1 -1
  30. package/dist/module/protected.js +1 -17
  31. package/dist/module/protected.js.map +1 -1
  32. package/dist/module/selector.js +36 -0
  33. package/dist/module/selector.js.map +1 -0
  34. package/dist/module/tuple.js.map +1 -1
  35. package/dist/types/deep.d.ts +284 -0
  36. package/dist/types/index.d.ts +10 -1
  37. package/dist/types/internal.d.ts +7 -4
  38. package/dist/types/match.d.ts +74 -80
  39. package/dist/types/patch.d.ts +57 -50
  40. package/dist/types/path.d.ts +177 -34
  41. package/dist/types/protected.d.ts +1 -16
  42. package/dist/types/selector.d.ts +47 -0
  43. package/dist/types/tuple.d.ts +10 -0
  44. package/package.json +3 -3
  45. package/src/deep.ts +364 -0
  46. package/src/index.ts +14 -10
  47. package/src/internal.ts +7 -4
  48. package/src/match.ts +396 -212
  49. package/src/patch.ts +173 -176
  50. package/src/path.ts +400 -74
  51. package/src/protected.ts +14 -25
  52. package/src/selector.ts +90 -0
  53. package/src/tuple.ts +12 -0
@@ -0,0 +1,284 @@
1
+ import type { Match, Patch, Path, Protected, Selector } from './internal';
2
+ export { match, type Match } from './match';
3
+ export { patch, type Patch } from './patch';
4
+ export { getAt, patchAt, type Path } from './path';
5
+ export { select, type Selector } from './selector';
6
+ export type { Protected } from './protected';
7
+ /**
8
+ * Returns the same value wrapped in the `Protected` type.
9
+ * @typeparam T - the source value type
10
+ * @param source - the value to wrap
11
+ * @note does not perform any runtime protection, it is only a utility to easily add the `Protected`
12
+ * type to a value
13
+ * @example
14
+ * ```ts
15
+ * const obj = Deep.protect({ a: 1, b: { c: true, d: [1] } })
16
+ * obj.a = 2 // compiler error: a is readonly
17
+ * obj.b.c = false // compiler error: c is readonly
18
+ * obj.b.d.push(2) // compiler error: d is a readonly array
19
+ * (obj as any).b.d.push(2) // will actually mutate the object
20
+ * ```
21
+ */
22
+ export declare function protect<T>(source: T): Protected<T>;
23
+ /**
24
+ * Returns a function that gets the value at the given string `path` inside an object.
25
+ * @typeparam T - the input value type
26
+ * @typeparam P - the string literal path type in the object
27
+ * @param path - the string path in the object
28
+ * @param source - the value from which to extract the path value
29
+ * @example
30
+ * ```ts
31
+ * const items = [{ a: { b: 1, c: 'a' } }, { a: { b: 2, c: 'b' } }];
32
+ * items.map(Deep.getAtWith('a.c'));
33
+ * // => ['a', 'b']
34
+ * ```
35
+ */
36
+ export declare function getAtWith<T, P extends Path.Get<T>>(path: P): (source: T) => Path.Result<T, P>;
37
+ /**
38
+ * Returns a function that patches a given `source` with the given `patchItems`.
39
+ * @typeparam T - the patch value type
40
+ * @typeparam TE - utility type
41
+ * @typeparam TT - utility type
42
+ * @param patchItem - the `Patch` definition to update the given value of type `T` with.
43
+ * @param source - the value to use the given `patchItem` on.
44
+ * @example
45
+ * ```ts
46
+ * const items = [{ a: 1, b: 'a' }, { a: 2, b: 'b' }];
47
+ * items.map(Deep.patchWith([{ a: v => v + 1 }]));
48
+ * // => [{ a: 2, b: 'a' }, { a: 3, b: 'b' }]
49
+ * ```
50
+ */
51
+ export declare function patchWith<T, TE extends T = T, TT = T>(patchItem: Patch<TT, TE>): (source: TE) => T;
52
+ /**
53
+ * Returns a function that patches a given `value` with the given `patchItems` at the given `path`.
54
+ * @typeparam T - the patch value type
55
+ * @typeparam P - the string literal path type in the object
56
+ * @typeparam TE - utility type
57
+ * @typeparam TT - utility type
58
+ * @param path - the string path in the object
59
+ * @param patchItem - the `Patch` definition to update the value at the given `path` in `T` with.
60
+ * @param source - the value to use the given `patchItem` on at the given `path`.
61
+ * @example
62
+ * ```ts
63
+ * const items = [{ a: { b: 1, c: 'a' } }, { a: { b: 2, c: 'b' } }];
64
+ * items.map(Deep.patchAtWith('a', [{ b: (v) => v + 1 }]));
65
+ * // => [{ a: { b: 2, c: 'a' } }, { a: { b: 3, c: 'b' } }]
66
+ * ```
67
+ */
68
+ export declare function patchAtWith<T, P extends Path.Set<T>, TE extends T = T, TT = T>(path: P, patchItem: Patch<Path.Result<TE, P>, Path.Result<TT, P>>): (source: T) => T;
69
+ /**
70
+ * Returns a function that matches a given `value` with the given `matcher`.
71
+ * @typeparam T - the patch value type
72
+ * @param matcher - a matcher object that matches input values.
73
+ * @param source - the value to use the given `patchItem` on at the given `path`.
74
+ * @example
75
+ * ```ts
76
+ * const items = [{ a: 1, b: 'a' }, { a: 2, b: 'b' }];
77
+ * items.filter(Deep.matchWith({ a: 2 }));
78
+ * // => [{ a: 2, b: 'b' }]
79
+ * ```
80
+ */
81
+ export declare function matchWith<T>(matcher: Match<T>): (source: T) => boolean;
82
+ /**
83
+ * Returns true if the given `value` object matches the given `matcher` at the given `path`, false otherwise.
84
+ * @typeparam T - the input value type
85
+ * @typeparam P - the string literal path type in the object
86
+ * @param source - the input value
87
+ * @param path - the string path in the object
88
+ * @param matcher - a matcher object or a function taking the matcher API and returning a match object
89
+ * @example
90
+ * ```ts
91
+ * const input = { a: 1, b: { c: true, d: 'a' } }
92
+ * Deep.matchAt(input, 'b', { c: true })
93
+ * // => true
94
+ * ```
95
+ */
96
+ export declare function matchAt<T, P extends Path.Get<T>>(source: T, path: P, matcher: Match<Path.Result<T, P>>): boolean;
97
+ /**
98
+ * Returns a function that matches a given `value` with the given `matcher` at the given string `path`.
99
+ * @typeparam T - the patch value type
100
+ * @typeparam P - the string literal path type in the object
101
+ * @typeparam TE - utility type
102
+ * @param path - the string path in the object
103
+ * @param matcher - a matcher object that matches input values.
104
+ * @param source - the value to use the given `matcher` on at the given `path`.
105
+ * @example
106
+ * ```ts
107
+ * const items = [{ a: { b: 1, c: 'a' } }, { a: { b: 2, c: 'b' } }];
108
+ * items.filter(Deep.matchAtWith('a.b', 2));
109
+ * // => [{ a: 2, b: 'b' }]
110
+ * ```
111
+ */
112
+ export declare function matchAtWith<T, P extends Path.Get<T>, TE extends T = T>(path: P, matcher: Match<Path.Result<T & TE, P>>): (source: T) => boolean;
113
+ /**
114
+ * Returns a function that selects a certain shape from a given `value` with the given `selector`.
115
+ * @typeparam T - the patch value type
116
+ * @typeparam SL - the selector shape type
117
+ * @param selector - a shape indicating the selection from the source values
118
+ * @param source - the value to use the given `selector` on.
119
+ * @example
120
+ * ```ts
121
+ * const items = [{ a: { b: 1, c: 'a' } }, { a: { b: 2, c: 'b' } }];
122
+ * items.map(Deep.selectWith({ q: 'a.c', z: ['a.b', v => v.a.b + 1] as const }));
123
+ * // => [{ q: 'a', z: [1, 2] }, { q: 'b', z: [2, 3] }]
124
+ * ```
125
+ */
126
+ export declare function selectWith<T, SL extends Selector<T>>(selector: Selector.Shape<SL>): (source: T) => Selector.Result<T, SL>;
127
+ /**
128
+ * Returns the result of applying the given `selector` shape to the given `source` value.
129
+ * @typeparam T - the patch value type
130
+ * @typeparam P - the string literal path type in the object
131
+ * @typeparam SL - the selector shape type
132
+ * @param source - the source value to select from
133
+ * @param path - the string path in the object
134
+ * @param selector - a shape indicating the selection from the source value at the given path
135
+ * @example
136
+ * ```ts
137
+ * const item = { a: { b: 1, c: 'a' } };
138
+ * Deep.selectAt(item, 'a', { q: 'c', z: ['b', v => v.b + 1] as const });
139
+ * // => { q: 'a', z: [1, 2] }
140
+ * ```
141
+ */
142
+ export declare function selectAt<T, P extends Path.Get<T>, SL extends Selector<Path.Result<T, P>>>(source: T, path: P, selector: Selector.Shape<SL>): Selector.Result<Path.Result<T, P>, SL>;
143
+ /**
144
+ * Returns a function that selects a certain shape from a given `value` with the given `selector` at the given string `path`.
145
+ * @typeparam T - the patch value type
146
+ * @typeparam P - the string literal path type in the object
147
+ * @typeparam SL - the selector shape type
148
+ * @param path - the string path in the object
149
+ * @param selector - a shape indicating the selection from the source values
150
+ * @example
151
+ * ```ts
152
+ * const items = [{ a: { b: 1, c: 'a' } }, { a: { b: 2, c: 'b' } }];
153
+ * items.map(Deep.selectAtWith('a', { q: 'c', z: ['b', v => v.b + 1] as const }));
154
+ * // => [{ q: 'a', z: [1, 2] }, { q: 'b', z: [2, 3] }]
155
+ * ```
156
+ */
157
+ export declare function selectAtWith<T, P extends Path.Get<T>, SL extends Selector<Path.Result<T, P>>>(path: P, selector: Selector.Shape<SL>): (source: T) => Selector.Result<Path.Result<T, P>, SL>;
158
+ /**
159
+ * Typed and curried Deep API, used in situations where the target type
160
+ * is known but the value will be applied later.
161
+ * @typeparam T - the target type
162
+ * @example
163
+ * ```ts
164
+ * const s = { a: 1, b: { c: 'a', d: true }};
165
+ * const upd = Deep.withType<typeof s>().patchWith([{ a: (v) => v + 1 }]);
166
+ * upd(s);
167
+ * // => { a: 2, b: { c: 'a', d: true }}
168
+ * ```
169
+ */
170
+ export interface WithType<T> {
171
+ /**
172
+ * Returns a function that given an object returns the value at the given `path`.
173
+ * @typeparam P - a Path in object type T
174
+ * @param path - the path into the object
175
+ * @example
176
+ * ```ts
177
+ * const value = { a: { b: { c: 5 } } }
178
+ * const getValue = Deep.withType<typeof value>().getAtWith('a.b.c');
179
+ * getValue(value);
180
+ * // => 5
181
+ * ```
182
+ */
183
+ getAtWith<P extends Path.Get<T>>(path: P): (source: T) => Path.Result<T, P>;
184
+ /**
185
+ * Returns a function that patches a given `value` with the given `patchItems`.
186
+ * @typeparam TT - utility type
187
+ * @param patchItem - the `Patch` definition to update the given value with
188
+ * @param source - the value to use the given `patchItem` on.
189
+ * @example
190
+ * ```ts
191
+ * const value = { a: 1, b: 'a' };
192
+ * const upd = Deep.withType<typeof value>().patch([{ a: v => v + 1 }]);
193
+ * upd(value);
194
+ * // => { a: 2, b: 'a' }
195
+ * ```
196
+ */
197
+ patchWith<TE extends T = T, TT = T>(patchItem: Patch<TT, TE>): (source: TE) => T;
198
+ /**
199
+ * Returns a function that patches a given `value` with the given `patchItems` at the given `path`.
200
+ * @typeparam P - the string literal path type in the object
201
+ * @typeparam TT - utility type
202
+ * @param path - the string path in the object
203
+ * @param patchItem - the `Patch` definition to update the given value with
204
+ * @param source - the value to use the given `patchItem` on at the given `path`.
205
+ * @example
206
+ * ```ts
207
+ * const value = { a: { b: 1, c: 'a' } };
208
+ * const upd = Deep.withType<typeof value>().patchAtWith('a', [{ b: (v) => v + 1 }])
209
+ * upd(value);
210
+ * // => { a: { b: 2, c: 'a' } }
211
+ * ```
212
+ */
213
+ patchAtWith<P extends Path.Set<T>, TT = T>(path: P, patchItem: Patch<Path.Result<T, P>, Path.Result<TT, P>>): (source: T) => T;
214
+ /**
215
+ * Returns a function that matches a given `value` with the given `matcher`.
216
+ * @param matcher - a matcher object that matches input values.
217
+ * @param source - the value to use the given `matcher` on.
218
+ * @example
219
+ * ```ts
220
+ * const value = { a: 1, b: 'a' };
221
+ * const m = Deep.withType<typeof value>().matchWith({ a: 1 });
222
+ * m(value);
223
+ * // => true
224
+ * ```
225
+ */
226
+ matchWith(matcher: Match<T>): (source: T) => boolean;
227
+ /**
228
+ * Returns a function that matches a given `value` with the given `matcher` at the given string `path`.
229
+ * @typeparam P - the string literal path type in the object
230
+ * @param path - the string path in the object
231
+ * @param matcher - a matcher object that matches input values.
232
+ * @param source - the value to use the given `matcher` on at the given `path`.
233
+ * @example
234
+ * ```ts
235
+ * const items = [{ a: { b: 1, c: 'a' } }, { a: { b: 2, c: 'b' } }];
236
+ * items.filter(Deep.matchAtWith('a.b', 2));
237
+ * // => [{ a: 2, b: 'b' }]
238
+ * ```
239
+ */
240
+ matchAtWith<P extends Path.Get<T>>(path: P, matcher: Match<Path.Result<T, P>>): (source: T) => boolean;
241
+ /**
242
+ * Returns a function that selects a certain shape from a given `value` with the given `selector`.
243
+ * @typeparam SL - the selector shape type
244
+ * @param selector - a shape indicating the selection from the source values
245
+ * @param source - the value to use the given `selector` on.
246
+ * @example
247
+ * ```ts
248
+ * const value = { a: { b: 1, c: 'a' } };
249
+ * const sel = Deep.withType<typeof value>().selectWith({ q: 'a.b' });
250
+ * sel(value);
251
+ * // => { q: 1 }
252
+ * ```
253
+ */
254
+ selectWith<SL extends Selector<T>>(selector: Selector.Shape<SL>): (source: T) => Selector.Result<T, SL>;
255
+ /**
256
+ * Returns a function that selects a certain shape from a given `value` with the given `selector` at the given string `path`.
257
+ * @typeparam P - the string literal path type in the object
258
+ * @typeparam SL - the selector shape type
259
+ * @param path - the string path in the object
260
+ * @param selector - a shape indicating the selection from the source values
261
+ * @param source - the value to use the given `selector` on at the given `path`.
262
+ * @example
263
+ * ```ts
264
+ * const value = { a: { b: 1, c: 'a' } };
265
+ * const sel = Deep.withType<typeof value>().selectAtWith('a', { q: 'b' });
266
+ * sel(value);
267
+ * // => { q: 1 }
268
+ * ```
269
+ */
270
+ selectAtWith<P extends Path.Get<T>, SL extends Selector<Path.Result<T, P>>>(path: P, selector: Selector.Shape<SL>): (source: T) => Selector.Result<Path.Result<T, P>, SL>;
271
+ }
272
+ /**
273
+ * Returns a curried API with a known target type. This can be useful for using the methods in
274
+ * contexts where the target type can be inferred from the usage.
275
+ * @typeparam T - the target type
276
+ * @example
277
+ * ```ts
278
+ * const s = { a: 1, b: { c: 'a', d: true }}
279
+ * const upd = Deep.withType<typeof s>().patchWith([{ d: (v) => !v }])
280
+ * upd(s)
281
+ * // => { a: 1, b: { c: 'a', d: false }}
282
+ * ```
283
+ */
284
+ export declare function withType<T>(): WithType<T>;
@@ -5,5 +5,14 @@
5
5
  * <br/>
6
6
  * See the [Rimbu docs Deep overview page](/docs/deep/overview) for more information.
7
7
  */
8
- export { patch, patchNested, Patch, match, Match, Path, Protected, } from './internal';
9
8
  export { Tuple } from './tuple';
9
+ export type { Protected, Patch } from './internal';
10
+ export { Path, type Selector, type Match } from './internal';
11
+ export * from './deep';
12
+ import * as Deep from './deep';
13
+ export {
14
+ /**
15
+ * Convenience namespace offering access to most common functions used in the `@rimbu/deep` package.
16
+ * These are mainly utilities to patch and match plain JavaScript objects.
17
+ */
18
+ Deep, };
@@ -1,4 +1,7 @@
1
- export * from './protected';
2
- export * from './match';
3
- export * from './patch';
4
- export * from './path';
1
+ export type { Protected } from './protected';
2
+ export { Path } from './path';
3
+ export { type Match } from './match';
4
+ export type { Patch } from './patch';
5
+ export type { Selector } from './selector';
6
+ import * as Deep from './deep';
7
+ export { Deep };
@@ -1,124 +1,118 @@
1
- import { type IsPlainObj, type PlainObj } from '@rimbu/base';
1
+ import { IsAnyFunc, IsArray, IsPlainObj, NotIterable } from '@rimbu/base';
2
2
  import type { Protected } from './internal';
3
+ import type { Tuple } from './tuple';
3
4
  /**
4
- * The type to determine the allowed input values for the `match` functions.
5
+ * The type to determine the allowed input values for the `match` function.
5
6
  * @typeparam T - the type of value to match
7
+ * @typeparam C - utility type
6
8
  */
7
- export declare type Match<T> = Match.Options<T, T>;
9
+ export declare type Match<T, C extends Partial<T> = Partial<T>> = Match.Entry<T, C, T, T>;
8
10
  export declare namespace Match {
9
11
  /**
10
- * The types of supported match input.
11
- * @typeparam T - the type of value to match
12
+ * Determines the various allowed match types for given type `T`.
13
+ * @typeparam T - the input value type
14
+ * @typeparam C - utility type
15
+ * @typeparam P - the parant type
12
16
  * @typeparam R - the root object type
13
17
  */
14
- type Options<T, R> = Every<T, R> | Some<T, R> | None<T, R> | Single<T, R> | Match.Obj<T, R>;
18
+ type Entry<T, C, P, R> = IsAnyFunc<T> extends true ? T : IsPlainObj<T> extends true ? Match.WithResult<T, P, R, Match.Obj<T, C, P, R>> : IsArray<T> extends true ? // determine allowed match values for array or tuple
19
+ Match.Arr<T, C, P, R> | Match.Func<T, P, R, Match.Arr<T, C, P, R>> : Match.WithResult<T, P, R, {
20
+ [K in keyof C]: C[K & keyof T];
21
+ }>;
15
22
  /**
16
- * The type to determine allowed matchers for objects.
17
- * @typeparam T - the type of value to match
23
+ * The type that determines allowed matchers for objects.
24
+ * @typeparam T - the input value type
25
+ * @typeparam C - utility type
26
+ * @typeparam P - the parant type
18
27
  * @typeparam R - the root object type
19
28
  */
20
- type Obj<T, R> = {
21
- [K in keyof T]?: Match.ObjItem<T[K], R> | ((current: Protected<T[K]>, parent: Protected<T>, root: Protected<R>) => boolean | Match.ObjItem<T[K], R>);
22
- };
29
+ type Obj<T, C, P, R> = Match.ObjProps<T, C, R> | Match.CompoundForObj<T, C, P, R>;
23
30
  /**
24
31
  * The type to determine allowed matchers for object properties.
25
- * @typeparam T - the type of value to match
32
+ * @typeparam T - the input value type
33
+ * @typeparam C - utility type
26
34
  * @typeparam R - the root object type
27
35
  */
28
- type ObjItem<T, R> = IsPlainObj<T> extends true ? Match.Options<T, R> : T extends Iterable<infer U> ? T | Iterable<U> : T;
36
+ type ObjProps<T, C, R> = {
37
+ [K in keyof C]?: K extends keyof T ? Match.Entry<T[K], C[K], T, R> : never;
38
+ };
29
39
  /**
30
- * Returns a matcher that returns true if every given `matchItem` matches the given value.
31
- * @typeparam T - the type of value to match
40
+ * The type that determines allowed matchers for arrays/tuples.
41
+ * @typeparam T - the input value type
42
+ * @typeparam C - utility type
43
+ * @typeparam P - the parant type
32
44
  * @typeparam R - the root object type
33
- * @typeparam Q - a utility type for the matcher
34
- * @param matchItems - the match specifications to test
35
- * @example
36
- * ```ts
37
- * const input = { a: 1, b: { c: true, d: 'a' } }
38
- * match(input, Match.every({ a: 1, { c: true } } )) // => true
39
- * match(input, Match.every({ a: 1, { c: false } } )) // => false
40
- * ```
41
45
  */
42
- function every<T, R, Q extends T = T>(...matchItems: Match.Options<Q, R>[]): Every<T, R, Q>;
46
+ type Arr<T, C, P, R> = C | Match.CompoundForArr<T, C, P, R> | (Match.TupIndices<T, C, R> & {
47
+ [K in Match.CompoundType]?: never;
48
+ });
49
+ type WithResult<T, P, R, S> = S | Match.Func<T, P, R, S>;
43
50
  /**
44
- * Returns a matcher that returns true if at least one of given `matchItem` matches the given value.
45
- * @typeparam T - the type of value to match
51
+ * Type used to determine the allowed function types. Always includes booleans.
52
+ * @typeparam T - the input value type
53
+ * @typeparam P - the parant type
46
54
  * @typeparam R - the root object type
47
- * @typeparam Q - a utility type for the matcher
48
- * @param matchItems - the match specifications to test
49
- * @example
50
- * ```ts
51
- * const input = { a: 1, b: { c: true, d: 'a' } }
52
- * match(input, Match.some({ a: 5, { c: true } } )) // => true
53
- * match(input, Match.some({ a: 5, { c: false } } )) // => false
54
- * ```
55
+ * @typeparam S - the allowed return value type
55
56
  */
56
- function some<T, R, Q extends T = T>(...matchItems: Match.Options<Q, R>[]): Some<T, R, Q>;
57
+ type Func<T, P, R, S> = (current: Protected<T>, parent: Protected<P>, root: Protected<R>) => boolean | S;
57
58
  /**
58
- * Returns a matcher that returns true if none of given `matchItem` matches the given value.
59
- * @typeparam T - the type of value to match
59
+ * Type used to indicate an object containing matches for tuple indices.
60
+ * @typeparam T - the input value type
61
+ * @typeparam C - utility type
60
62
  * @typeparam R - the root object type
61
- * @typeparam Q - a utility type for the matcher
62
- * @param matchItems - the match specifications to test
63
- * @example
64
- * ```ts
65
- * const input = { a: 1, b: { c: true, d: 'a' } }
66
- * match(input, Match.none({ a: 5, { c: true } } )) // => false
67
- * match(input, Match.none({ a: 5, { c: false } } )) // => true
68
- * ```
69
63
  */
70
- function none<T, R, Q extends T = T>(...matchItems: Match.Options<Q, R>[]): None<T, R, Q>;
64
+ type TupIndices<T, C, R> = {
65
+ [K in Tuple.KeysOf<C>]?: Match.Entry<T[K & keyof T], C[K], T, R>;
66
+ } & NotIterable;
67
+ /**
68
+ * Compound keys used to indicate the type of compound.
69
+ */
70
+ type CompoundType = 'every' | 'some' | 'none' | 'single';
71
71
  /**
72
- * Returns a matcher that returns true if exactly one of given `matchItem` matches the given value.
73
- * @typeparam T - the type of value to match
72
+ * Compount matcher for objects, can only be an array staring with a compound type keyword.
73
+ * @typeparam T - the input value type
74
+ * @typeparam C - utility type
75
+ * @typeparam P - the parent type
74
76
  * @typeparam R - the root object type
75
- * @typeparam Q - a utility type for the matcher
76
- * @param matchItems - the match specifications to test
77
- * @example
78
- * ```ts
79
- * const input = { a: 1, b: { c: true, d: 'a' } }
80
- * match(input, Match.single({ a: 1, { c: true } } )) // => false
81
- * match(input, Match.single({ a: 1, { c: false } } )) // => true
82
- * ```
83
77
  */
84
- function single<T, R, Q extends T = T>(...matchItems: Match.Options<Q, R>[]): Single<T, R, Q>;
78
+ type CompoundForObj<T, C, P, R> = [
79
+ Match.CompoundType,
80
+ ...Match.Entry<T, C, P, R>[]
81
+ ];
85
82
  /**
86
- * The functions that are optionally provided to a match function.
83
+ * Defines an object containing exactly one `CompoundType` key, having an array of matchers.
84
+ * @typeparam T - the input value type
85
+ * @typeparam C - utility type
86
+ * @typeparam P - the parent type
87
+ * @typeparam R - the root object type
87
88
  */
88
- type Api = typeof Match;
89
- }
90
- declare class Every<T, R, Q extends T = T> {
91
- readonly matchItems: Match.Options<Q, R>[];
92
- constructor(matchItems: Match.Options<Q, R>[]);
93
- }
94
- declare class Some<T, R, Q extends T = T> {
95
- readonly matchItems: Match.Options<Q, R>[];
96
- constructor(matchItems: Match.Options<Q, R>[]);
97
- }
98
- declare class None<T, R, Q extends T = T> {
99
- readonly matchItems: Match.Options<Q, R>[];
100
- constructor(matchItems: Match.Options<Q, R>[]);
101
- }
102
- declare class Single<T, R, Q extends T = T> {
103
- readonly matchItems: Match.Options<Q, R>[];
104
- constructor(matchItems: Match.Options<Q, R>[]);
89
+ type CompoundForArr<T, C, P, R> = {
90
+ [K in CompoundType]: {
91
+ [K2 in CompoundType]?: K2 extends K ? Match.Entry<T, C, P, R>[] : never;
92
+ };
93
+ }[CompoundType];
94
+ /**
95
+ * Utility type for collecting errors
96
+ */
97
+ type ErrorCollector = string[] | undefined;
105
98
  }
106
99
  /**
107
100
  * Returns true if the given `value` object matches the given `matcher`, false otherwise.
108
101
  * @typeparam T - the input value type
109
- * @param value - the value to match (should be a plain object)
102
+ * @typeparam C - utility type
103
+ * @param source - the value to match (should be a plain object)
110
104
  * @param matcher - a matcher object or a function taking the matcher API and returning a match object
105
+ * @param errorCollector - (optional) a string array that can be passed to collect reasons why the match failed
111
106
  * @example
112
107
  * ```ts
113
108
  * const input = { a: 1, b: { c: true, d: 'a' } }
114
109
  * match(input, { a: 1 }) // => true
115
110
  * match(input, { a: 2 }) // => false
116
- * match(input, { a: v => v > 10 }) // => false
111
+ * match(input, { a: (v) => v > 10 }) // => false
117
112
  * match(input, { b: { c: true }}) // => true
118
- * match(input, ({ every }) => every({ a: v => v > 0 }, { b: { c: true } } )) // => true
113
+ * match(input, (['every', { a: (v) => v > 0 }, { b: { c: true } }]) // => true
119
114
  * match(input, { b: { c: (v, parent, root) => v && parent.d.length > 0 && root.a > 0 } })
120
115
  * // => true
121
116
  * ```
122
117
  */
123
- export declare function match<T>(value: T & PlainObj<T>, matcher: Match<T> | ((matchApi: Match.Api) => Match<T>)): boolean;
124
- export {};
118
+ export declare function match<T, C extends Partial<T> = Partial<T>>(source: T, matcher: Match<T, C>, errorCollector?: Match.ErrorCollector): boolean;
@@ -1,82 +1,89 @@
1
- import { type AnyFunc, type PlainObj } from '@rimbu/base';
1
+ import { IsAnyFunc, IsArray, IsPlainObj } from '@rimbu/base';
2
2
  import type { Protected } from './internal';
3
+ import type { Tuple } from './tuple';
3
4
  /**
4
5
  * A type to determine the allowed input type for the `patch` function.
5
6
  * @typeparam T - the input type to be patched
6
7
  */
7
- export declare type Patch<T> = Patch.Entry<T, T>;
8
+ export declare type Patch<T, C = T> = Patch.Entry<T, C, T, T>;
8
9
  export declare namespace Patch {
9
10
  /**
10
11
  * The entry type for a (nested) patch. Can be either a patch object or a function accepting the nested patch function and returning a patch object.
11
12
  * @typeparam T - the input value type
13
+ * @typeparam C - a utility type
14
+ * @typeparam P - the parent type
12
15
  * @typeparam R - the root object type
13
16
  */
14
- type Entry<T, R> = Patch.Obj<T, R> | ((patchNested: Patch.Nested) => Patch.Obj<T, R>);
17
+ type Entry<T, C, P, R> = IsAnyFunc<T> extends true ? T : IsPlainObj<T> extends true ? Patch.WithResult<T, P, R, Patch.Obj<T, C, R>> : Tuple.IsTuple<T> extends true ? Patch.WithResult<T, P, R, T | Patch.Tup<T, C, R>> : IsArray<T> extends true ? Patch.WithResult<T, P, R, T> : Patch.WithResult<T, P, R, T>;
15
18
  /**
16
- * The object patch type, allows the user to specify keys in T that should be patched, and each given key contains either a new value or a nested patch, or a function receiving
17
- * the current value, the parent object, and the root object, and returning a new value or a nested patch.
18
- * @typeparam T - the input value type
19
- * @typeparam R - the root object type
19
+ * Either result type S, or a patch function with the value type, the parent type, and the root type.
20
+ * @typeparam T - the value type
21
+ * @typeparam P - the parent type
22
+ * @typeparam R - the root type
23
+ * @typeparam S - the result type
24
+ */
25
+ type WithResult<T, P, R, S> = S | Patch.Func<T, P, R, S>;
26
+ /**
27
+ * A function patch type that is a function taking the current value, the parent and root values,
28
+ * and returns a return value.
29
+ * @typeparam T - the value type
30
+ * @typeparam P - the parent type
31
+ * @typeparam R - the root type
32
+ * @typeparam S - the result type
33
+ */
34
+ type Func<T, P, R, S> = (current: Protected<T>, parent: Protected<P>, root: Protected<R>) => Protected<S>;
35
+ /**
36
+ * A type defining the allowed patch values for tuples.
37
+ * @typeparam T - the input tuple type
38
+ * @typeparam C - a utility type
39
+ * @typeparam R - the root type
40
+ */
41
+ type Tup<T, C, R> = {
42
+ [K in Tuple.KeysOf<T>]?: Patch.Entry<T[K & keyof T], C[K & keyof C], T, R>;
43
+ } & NotIterable;
44
+ /**
45
+ * Utility type to exclude Iterable types.
20
46
  */
21
- type Obj<T, R> = {
22
- [K in keyof T]?: (T[K] extends AnyFunc ? never : ObjItem<T[K], R>) | ((cur: Protected<T[K]>, parent: Protected<T>, root: Protected<R>) => ObjItem<T[K], R>);
47
+ type NotIterable = {
48
+ [Symbol.iterator]?: never;
23
49
  };
24
50
  /**
25
- * A patch object can have as update either a new value or a nested patch object
51
+ * A type defining the allowed patch values for objects.
26
52
  * @typeparam T - the input value type
53
+ * @typeparam C - a utility type
27
54
  * @typeparam R - the root object type
28
55
  */
29
- type ObjItem<T, R> = T | NestedObj<T, R>;
30
- /**
31
- * The function type to create a nested Patch object.
32
- */
33
- type Nested = typeof patchNested;
56
+ type Obj<T, C, R> = T | Patch.ObjProps<T, C, R>[];
34
57
  /**
35
- * Returns a function that patches a given `value` with the given `patchItems`.
36
- * @typeparam T - the patch value type
37
- * @typeparam Q - the input value type
38
- * @param patchItems - a number of `Patch` objects that patch a given value of type T.
39
- * @example
40
- * ```ts
41
- * const items = [{ a: 1, b: 'a' }, { a: 2, b: 'b' }]
42
- * items.map(Patch.create({ a: v => v + 1 }))
43
- * // => [{ a: 2, b: 'a' }, { a: 3, b: 'b' }]
44
- * ```
58
+ * A type defining the allowed patch values for object properties.
59
+ * @typeparam T - the input value type
60
+ * @typeparam C - a utility type
61
+ * @typeparam R - the root object type
45
62
  */
46
- function create<T, Q extends T = T>(...patchItems: Patch<T & Q>[]): (value: Q & PlainObj<Q>) => Q;
47
- }
48
- declare class NestedObj<T, R, Q extends T = T> {
49
- readonly patchDataItems: Patch.Obj<Q, R>[];
50
- constructor(patchDataItems: Patch.Obj<Q, R>[]);
63
+ type ObjProps<T, C, R> = {
64
+ [K in keyof C]?: K extends keyof T ? Patch.Entry<T[K], C[K], T, R> : never;
65
+ };
51
66
  }
52
- /**
53
- * Returns a nested patch object based on the given `patchDataItems` that work on a subpart
54
- * of a larger object to be patched.
55
- * @typeparam T - the input value type
56
- * @typeparam R - the root object type
57
- * @typeparam Q - the patch type
58
- * @param patchDataItems - a number of `Patch` objects to be applied to the subpart of the object
59
- * @example
60
- * ```ts
61
- * patch({ a: 1, b: { c: true, d: 'a' } }, { b: patchNested({ d: 'b' }) })
62
- * // => { a: 1, b: { c: true, d: 'b' } }
63
- * ```
64
- */
65
- export declare function patchNested<T, R, Q extends T = T>(...patchDataItems: Patch.Obj<Q, R>[]): NestedObj<T, R, Q>;
66
67
  /**
67
68
  * Returns an immutably updated version of the given `value` where the given `patchItems` have been
68
69
  * applied to the result.
70
+ * The Rimbu patch notation is as follows:
71
+ * - if the target is a simple value or array, the patch can be the same type or a function returning the same type
72
+ * - if the target is a tuple (array of fixed length), the patch be the same type or an object containing numeric keys with patches indicating the tuple index to patch
73
+ * - if the target is an object, the patch can be the same type, or an array containing partial keys with their patches for the object
74
+ * @typeparam T - the type of the value to patch
75
+ * @typeparam TE - a utility type
76
+ * @typeparam TT - a utility type
69
77
  * @param value - the input value to patch
70
- * @param patchItems - the `Patch` objects to apply to the input value
78
+ * @param patchItem - the `Patch` value to apply to the input value
71
79
  * @example
72
80
  * ```ts
73
81
  * const input = { a: 1, b: { c: true, d: 'a' } }
74
- * patch(input, { a: 2 }) // => { a: 2, b: { c: true, d: 'a' } }
75
- * patch(input: ($) => ({ b: $({ c: v => !v }) }) )
82
+ * patch(input, [{ a: 2 }]) // => { a: 2, b: { c: true, d: 'a' } }
83
+ * patch(input, [{ b: [{ c: (v) => !v }] }] )
76
84
  * // => { a: 1, b: { c: false, d: 'a' } }
77
- * patch(input: ($) => ({ a: v => v + 1, b: $({ d: 'q' }) }) )
85
+ * patch(input: [{ a: (v) => v + 1, b: [{ d: 'q' }] }] )
78
86
  * // => { a: 2, b: { c: true, d: 'q' } }
79
87
  * ```
80
88
  */
81
- export declare function patch<T>(value: T & PlainObj<T>, ...patchItems: Patch<T>[]): T;
82
- export {};
89
+ export declare function patch<T, TE extends T = T, TT = T>(value: T, patchItem: Patch<TE, T & TT>): T;