@rimbu/deep 0.9.2 → 0.10.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.
Files changed (49) hide show
  1. package/dist/main/index.js +12 -3
  2. package/dist/main/index.js.map +1 -1
  3. package/dist/main/internal.js +2 -4
  4. package/dist/main/internal.js.map +1 -1
  5. package/dist/main/match.js +197 -132
  6. package/dist/main/match.js.map +1 -1
  7. package/dist/main/patch.js +125 -106
  8. package/dist/main/patch.js.map +1 -1
  9. package/dist/main/path.js +12 -38
  10. package/dist/main/path.js.map +1 -1
  11. package/dist/main/protected.js +12 -0
  12. package/dist/main/protected.js.map +1 -0
  13. package/dist/module/index.js +3 -2
  14. package/dist/module/index.js.map +1 -1
  15. package/dist/module/internal.js +2 -4
  16. package/dist/module/internal.js.map +1 -1
  17. package/dist/module/match.js +180 -97
  18. package/dist/module/match.js.map +1 -1
  19. package/dist/module/patch.js +113 -87
  20. package/dist/module/patch.js.map +1 -1
  21. package/dist/module/path.js +12 -34
  22. package/dist/module/path.js.map +1 -1
  23. package/dist/module/protected.js +8 -0
  24. package/dist/module/protected.js.map +1 -0
  25. package/dist/types/index.d.ts +3 -2
  26. package/dist/types/internal.d.ts +2 -4
  27. package/dist/types/match.d.ts +93 -80
  28. package/dist/types/patch.d.ts +64 -61
  29. package/dist/types/path.d.ts +9 -20
  30. package/dist/types/protected.d.ts +13 -0
  31. package/package.json +4 -4
  32. package/src/index.ts +12 -2
  33. package/src/internal.ts +3 -4
  34. package/src/match.ts +254 -163
  35. package/src/patch.ts +204 -147
  36. package/src/path.ts +18 -43
  37. package/src/protected.ts +25 -0
  38. package/dist/main/immutable.js +0 -12
  39. package/dist/main/immutable.js.map +0 -1
  40. package/dist/main/literal.js +0 -41
  41. package/dist/main/literal.js.map +0 -1
  42. package/dist/module/immutable.js +0 -8
  43. package/dist/module/immutable.js.map +0 -1
  44. package/dist/module/literal.js +0 -37
  45. package/dist/module/literal.js.map +0 -1
  46. package/dist/types/immutable.d.ts +0 -13
  47. package/dist/types/literal.d.ts +0 -48
  48. package/src/immutable.ts +0 -21
  49. package/src/literal.ts +0 -70
@@ -9,13 +9,13 @@ export var Path;
9
9
  * @param path - the path into the object
10
10
  * @example
11
11
  * ```ts
12
- * console.log(Path.getValue({ a: { b: { c: 5 } } }), 'a.b')
12
+ * console.log(Path.get({ a: { b: { c: 5 } } }), 'a.b')
13
13
  * // => { c: 5 }
14
- * console.log(Path.getValue({ a: { b: { c: 5 } } }), 'a.b.c')
14
+ * console.log(Path.get({ a: { b: { c: 5 } } }), 'a.b.c')
15
15
  * // => 5
16
16
  * ```
17
17
  */
18
- function getValue(source, path) {
18
+ function get(source, path) {
19
19
  const items = path.split('.');
20
20
  let result = source;
21
21
  for (const item of items) {
@@ -23,7 +23,7 @@ export var Path;
23
23
  }
24
24
  return result;
25
25
  }
26
- Path.getValue = getValue;
26
+ Path.get = get;
27
27
  /**
28
28
  * Sets the value at the given path in the source to the given value.
29
29
  * @param source - the object to update
@@ -31,44 +31,22 @@ export var Path;
31
31
  * @param value - the new value to set at the given position
32
32
  * @example
33
33
  * ```ts
34
- * console.log(Path.setValue({ a: { b: { c: 5 } } }))
34
+ * console.log(Path.update({ a: { b: { c: 5 } } }, 'a.b.c', v => v + 5)
35
+ * // => { a: { b: { c: 6 } } }
35
36
  * ```
36
37
  */
37
- function setValue(source, path, value) {
38
+ function update(source, path, value) {
38
39
  const items = path.split('.');
39
40
  const last = items.pop();
40
- const result = Object.assign({}, source);
41
- let current = result;
41
+ const root = {};
42
+ let current = root;
42
43
  for (const item of items) {
43
- current[item] = Object.assign({}, current[item]);
44
+ current[item] = {};
44
45
  current = current[item];
45
46
  }
46
- const oldValue = current[last];
47
- if (Object.is(oldValue, value))
48
- return source;
49
47
  current[last] = value;
50
- return result;
51
- }
52
- Path.setValue = setValue;
53
- /**
54
- * Patches the value at the given path in the source to the given value using the given
55
- * `patches`.
56
- * @param source - the object to update
57
- * @param path - the path in the object to update
58
- * @param patches - one or more patches to update the value at the given path
59
- * @example
60
- * ```ts
61
- * console.log(Path.setValue({ a: { b: { c: 5 } } }, 'a.b.c', 8)
62
- * // => { a: { b: { c: 8 } } }
63
- * ```
64
- */
65
- function patchValue(source, path, ...patches) {
66
- const value = Path.getValue(source, path);
67
- const newValue = patch(value)(...patches);
68
- if (Object.is(value, newValue))
69
- return source;
70
- return Path.setValue(source, path, newValue);
48
+ return patch(source, root);
71
49
  }
72
- Path.patchValue = patchValue;
50
+ Path.update = update;
73
51
  })(Path || (Path = {}));
74
52
  //# sourceMappingURL=path.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"path.js","sourceRoot":"","sources":["../../src/path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,EAAS,MAAM,YAAY,CAAC;AAcnD,MAAM,KAAW,IAAI,CAiHpB;AAjHD,WAAiB,IAAI;IAwBnB;;;;;;;;;;;;;OAaG;IACH,SAAgB,QAAQ,CACtB,MAAS,EACT,IAAO;QAEP,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAE9B,IAAI,MAAM,GAAQ,MAAM,CAAC;QAEzB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;YACxB,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;SACvB;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAbe,aAAQ,WAavB,CAAA;IAED;;;;;;;;;OASG;IACH,SAAgB,QAAQ,CACtB,MAAS,EACT,IAAO,EACP,KAAwB;QAExB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,EAAG,CAAC;QAE1B,MAAM,MAAM,qBAAQ,MAAM,CAAE,CAAC;QAE7B,IAAI,OAAO,GAAQ,MAAM,CAAC;QAE1B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;YACxB,OAAO,CAAC,IAAI,CAAC,qBAAQ,OAAO,CAAC,IAAI,CAAC,CAAE,CAAC;YACrC,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;SACzB;QAED,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAE/B,IAAI,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC;YAAE,OAAO,MAAM,CAAC;QAE9C,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;QAEtB,OAAO,MAAM,CAAC;IAChB,CAAC;IAxBe,aAAQ,WAwBvB,CAAA;IAED;;;;;;;;;;;OAWG;IACH,SAAgB,UAAU,CACxB,MAAS,EACT,IAAO,EACP,GAAG,OAAuC;QAE1C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC;QAE1C,IAAI,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC;YAAE,OAAO,MAAM,CAAC;QAE9C,OAAO,IAAI,CAAC,QAAQ,CAAW,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IACzD,CAAC;IAXe,eAAU,aAWzB,CAAA;AACH,CAAC,EAjHgB,IAAI,KAAJ,IAAI,QAiHpB"}
1
+ {"version":3,"file":"path.js","sourceRoot":"","sources":["../../src/path.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAcnC,MAAM,KAAW,IAAI,CAqFpB;AArFD,WAAiB,IAAI;IAwBnB;;;;;;;;;;;;;OAaG;IACH,SAAgB,GAAG,CACjB,MAAuB,EACvB,IAAO;QAEP,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAE9B,IAAI,MAAM,GAAQ,MAAM,CAAC;QAEzB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;YACxB,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;SACvB;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAbe,QAAG,MAalB,CAAA;IAED;;;;;;;;;;OAUG;IACH,SAAgB,MAAM,CACpB,MAAuB,EACvB,IAAO,EACP,KAAgC;QAEhC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,EAAG,CAAC;QAE1B,MAAM,IAAI,GAAwB,EAAE,CAAC;QAErC,IAAI,OAAO,GAAG,IAAI,CAAC;QAEnB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;YACxB,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACnB,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;SACzB;QAED,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;QAEtB,OAAO,KAAK,CAAI,MAAM,EAAE,IAAI,CAAC,CAAC;IAChC,CAAC;IApBe,WAAM,SAoBrB,CAAA;AACH,CAAC,EArFgB,IAAI,KAAJ,IAAI,QAqFpB"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Returns the same value wrapped in the Protected type
3
+ * @param value - the value to wrap
4
+ */
5
+ export function Protected(value) {
6
+ return value;
7
+ }
8
+ //# sourceMappingURL=protected.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protected.js","sourceRoot":"","sources":["../../src/protected.ts"],"names":[],"mappings":"AAkBA;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAI,KAAQ;IACnC,OAAO,KAAY,CAAC;AACtB,CAAC"}
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * @packageDocumentation
3
3
  *
4
- * The `@rimbu/deep` package provides utilities to patch and match plain JavaScript objects..<br/>
4
+ * The `@rimbu/deep` package provides utilities to patch and match plain JavaScript objects.<br/>
5
5
  * <br/>
6
6
  * See the [Rimbu docs Deep overview page](/docs/deep/overview) for more information.
7
7
  */
8
- export * from './internal';
8
+ export { patch, patchNested, Patch, match, Match, Path, Protected, } from './internal';
9
+ export { Tuple } from './tuple';
@@ -1,6 +1,4 @@
1
- export * from './tuple';
2
- export * from './literal';
3
- export * from './immutable';
1
+ export * from './protected';
4
2
  export * from './match';
5
- export * from './path';
6
3
  export * from './patch';
4
+ export * from './path';
@@ -1,111 +1,124 @@
1
- import type { ArrayNonEmpty } from '@rimbu/common';
2
- import { Immutable, Literal } from './internal';
1
+ import { type IsPlainObj, type PlainObj } from '@rimbu/base';
2
+ import type { Protected } from './internal';
3
3
  /**
4
- * Type to determine the allowed input type for the `match` functions.
5
- * @typeparam T - the input type
6
- * @typeparam P - the parant type
7
- * @typeparam R - the root type
4
+ * The type to determine the allowed input values for the `match` functions.
5
+ * @typeparam T - the type of value to match
8
6
  */
9
- export declare type Match<T> = MatchHelper<T, T, T>;
10
- declare type MatchHelper<T, P, R> = T extends Literal.Obj ? Match.MatchObj<T, P, R> : T extends readonly any[] ? Match.MatchArray<T, P, R> : Match.Compare<T, P, R>;
7
+ export declare type Match<T> = Match.Options<T, T>;
11
8
  export declare namespace Match {
12
9
  /**
13
- * Type to determine the allowed input type for `match` functions given an object type T.
14
- * @typeparam T - the input type, being an object
15
- * @typeparam P - the parant type
16
- * @typeparam R - the root type
10
+ * The types of supported match input.
11
+ * @typeparam T - the type of value to match
12
+ * @typeparam R - the root object type
17
13
  */
18
- type MatchObj<T, P, R> = (Match.Compare<T, P, R> | {
19
- [K in keyof T]?: MatchHelper<T[K], T, R>;
20
- }) & Literal.NoIterable;
14
+ type Options<T, R> = Every<T, R> | Some<T, R> | None<T, R> | Single<T, R> | Match.Obj<T, R>;
21
15
  /**
22
- * Type representing at least one Match object for type T
23
- * @typeparam T - the target type
16
+ * The type to determine allowed matchers for objects.
17
+ * @typeparam T - the type of value to match
18
+ * @typeparam R - the root object type
24
19
  */
25
- type Multi<T> = ArrayNonEmpty<Match<T>>;
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
+ };
26
23
  /**
27
- * Type representing matchers for values that are not objects or arrays
28
- * @typeparam T - the input type
29
- * @typeparam P - the parant type
30
- * @typeparam R - the root type
24
+ * The type to determine allowed matchers for object properties.
25
+ * @typeparam T - the type of value to match
26
+ * @typeparam R - the root object type
31
27
  */
32
- type Compare<T, P, R> = Literal.Value<T> | ((value: Immutable<T>, parent: Immutable<P>, root: Immutable<R>) => boolean);
28
+ type ObjItem<T, R> = IsPlainObj<T> extends true ? Match.Options<T, R> : T extends Iterable<infer U> ? T | Iterable<U> : T;
33
29
  /**
34
- * Type representing allowed matchers for arrays
35
- * @typeparam T - the array type
36
- * @typeparam P - the parent type
37
- * @typeparam R - the root type
38
- */
39
- type MatchArray<T extends readonly any[], P, R> = (Match.Compare<T, P, R> | {
40
- [K in {
41
- [K2 in keyof T]: K2;
42
- }[keyof T]]?: MatchHelper<T[K], T, R>;
43
- }) & Literal.NoIterable;
44
- /**
45
- * Returns true if the given `value` matches all of the given objects in the `matchers` array.
46
- * @typeparam T - the type of the object to match
47
- * @param value - the value to match
48
- * @param matchers - one or more `Match` objects
30
+ * Returns a matcher that returns true if every given `matchItem` matches the given value.
31
+ * @typeparam T - the type of value to match
32
+ * @typeparam R - the root object type
33
+ * @typeparam Q - a utility type for the matcher
34
+ * @param matchItems - the match specifications to test
49
35
  * @example
50
36
  * ```ts
51
- * matchAll({ g: { h: 'abc' }})({ g: { h: 'a' }}) => false
52
- * matchAll({ g: { h: 'abc' }})({ g: { h: v => v.length > 1 }}) => true
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
53
40
  * ```
54
41
  */
55
- function all<T>(value: T): (...matchers: Match.Multi<T>) => boolean;
42
+ function every<T, R, Q extends T = T>(...matchItems: Match.Options<Q, R>[]): Every<T, R, Q>;
56
43
  /**
57
- * Returns true if the given `value` matches any of the given objects in the `matchers` array.
58
- * @typeparam T - the type of the object to match
59
- * @param value - the value to match
60
- * @param matchers - one or more `Match` objects
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
46
+ * @typeparam R - the root object type
47
+ * @typeparam Q - a utility type for the matcher
48
+ * @param matchItems - the match specifications to test
61
49
  * @example
62
50
  * ```ts
63
- * matchAny({ g: { h: 'abc' }})({ g: { h: 'a' }}, { g: { h: v => v.length < 2 }}) => false
64
- * matchAny({ g: { h: 'abc' }})({ g: { h: 'a' }}, { g: { h: v => v.length > 1 }}) => true
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
65
54
  * ```
66
55
  */
67
- function any<T>(value: T): (...matchers: Match.Multi<T>) => boolean;
56
+ function some<T, R, Q extends T = T>(...matchItems: Match.Options<Q, R>[]): Some<T, R, Q>;
68
57
  /**
69
- * Returns a function that takes a value of type T, and returns true if the value matches all the
70
- * given `matches` array of Match instances.
71
- * @typeparam T - the type of the object to match
72
- * @typeparam T2 - the type to use for the Match, should be equal to T
73
- * @param matches - at least one Match instance to perform on a given `value`
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
60
+ * @typeparam R - the root object type
61
+ * @typeparam Q - a utility type for the matcher
62
+ * @param matchItems - the match specifications to test
74
63
  * @example
75
64
  * ```ts
76
- * type Person = { name: string, age: number }
77
- * const m = Match.createAll<Person>({ age: v => v > 20 }, { name: v => v.length > 2 })
78
- *
79
- * console.log(m({ name: 'abc', age: 10 }))
80
- * // => false
81
- * console.log(m({ name: 'abc', age: 20 }))
82
- * // => true
83
- * console.log(m({ name: 'a', age: 20 }))
84
- * // => false
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
85
68
  * ```
86
69
  */
87
- function createAll<T, T2 extends T = T>(...matches: Match.Multi<T2>): (value: T) => boolean;
70
+ function none<T, R, Q extends T = T>(...matchItems: Match.Options<Q, R>[]): None<T, R, Q>;
88
71
  /**
89
- * Returns a function that takes a value of type T, and returns true if the value matches any of the
90
- * given `matches` array of Match instances.
91
- * @typeparam T - the type of the object to match
92
- * @typeparam T2 - the type to use for the Match, should be equal to T
93
- * @param matches - at least one Match instance to perform on a given `value`
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
74
+ * @typeparam R - the root object type
75
+ * @typeparam Q - a utility type for the matcher
76
+ * @param matchItems - the match specifications to test
94
77
  * @example
95
78
  * ```ts
96
- * type Person = { name: string, age: number }
97
- * const m = Match.createAny<Person>({ age: v => v > 20 }, { name: v => v.length > 2 })
98
- *
99
- * console.log(m({ name: 'abc', age: 10 }))
100
- * // => true
101
- * console.log(m({ name: 'abc', age: 20 }))
102
- * // => true
103
- * console.log(m({ name: 'a', age: 20 }))
104
- * // => true
105
- * console.log(m({ name: 'a', age: 10 }))
106
- * // => false
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
107
82
  * ```
108
83
  */
109
- function createAny<T, T2 extends T = T>(...matches: Match.Multi<T2>): (value: T) => boolean;
84
+ function single<T, R, Q extends T = T>(...matchItems: Match.Options<Q, R>[]): Single<T, R, Q>;
85
+ /**
86
+ * The functions that are optionally provided to a match function.
87
+ */
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>[]);
110
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>[]);
105
+ }
106
+ /**
107
+ * Returns true if the given `value` object matches the given `matcher`, false otherwise.
108
+ * @typeparam T - the input value type
109
+ * @param value - the value to match (should be a plain object)
110
+ * @param matcher - a matcher object or a function taking the matcher API and returning a match object
111
+ * @example
112
+ * ```ts
113
+ * const input = { a: 1, b: { c: true, d: 'a' } }
114
+ * match(input, { a: 1 }) // => true
115
+ * match(input, { a: 2 }) // => false
116
+ * match(input, { a: v => v > 10 }) // => false
117
+ * match(input, { b: { c: true }}) // => true
118
+ * match(input, ({ every }) => every({ a: v => v > 0 }, { b: { c: true } } )) // => true
119
+ * match(input, { b: { c: (v, parent, root) => v && parent.d.length > 0 && root.a > 0 } })
120
+ * // => true
121
+ * ```
122
+ */
123
+ export declare function match<T>(value: T & PlainObj<T>, matcher: Match<T> | ((matchApi: Match.Api) => Match<T>)): boolean;
111
124
  export {};
@@ -1,79 +1,82 @@
1
- import type { ArrayNonEmpty } from '@rimbu/common';
2
- import { Literal } from './internal';
1
+ import { type AnyFunc, type PlainObj } from '@rimbu/base';
2
+ import type { Protected } from './internal';
3
3
  /**
4
- * Type to determine the allowed input type for the `patch` function.
5
- * @typeparam T - the input type
6
- * @typeparam P - the parant type
7
- * @typeparam R - the root type
4
+ * A type to determine the allowed input type for the `patch` function.
5
+ * @typeparam T - the input type to be patched
8
6
  */
9
- export declare type Patch<T> = PatchHelper<T, T, T>;
10
- declare type PatchHelper<T, P, R> = T extends Literal.Obj ? Patch.PatchObj<T, P, R> : T extends readonly unknown[] ? Patch.PatchArray<T, P, R> : Patch.Update<T, P, R>;
11
- /**
12
- * Returns an updated version of given `value`, without modifying the value, where the contents
13
- * are updated according to the given `patches` Patch array.
14
- * @typeparam T - the type of the value to patch
15
- * @param value - the value to update
16
- * @param patches - one or more `Patch` objects indicating modifications to the value
17
- * @example
18
- * ```ts
19
- * patch({ g: { h: 5 }})({ g: { h: 6 }}) // => { g: { h: 6 }}
20
- * patch({ g: { h: 5 }})({ g: { h: v => v + 1 }}) // => { g: { h: 6 }}
21
- * patch({ g: { h: 5 }})({ g: { h: 1 }}, { g: { h: v => v + 1 }})
22
- * // => { g: { h: 2 }}
23
- * patch({ a: 1, b: 3 })({ a: (v, p) => v * p.b, (v, p) => v + p.a })
24
- * // => { a: 3, b: 4 }
25
- * ```
26
- */
27
- export declare function patch<T>(value: T): (...patches: Patch.Multi<T>) => T;
7
+ export declare type Patch<T> = Patch.Entry<T, T>;
28
8
  export declare namespace Patch {
29
- const MAP: unique symbol;
30
9
  /**
31
- * Type to determine the allowed input type for the `patch` function given an object type T.
32
- * @typeparam T - the input type, being an object
33
- * @typeparam P - the parant type
34
- * @typeparam R - the root type
10
+ * 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
+ * @typeparam T - the input value type
12
+ * @typeparam R - the root object type
35
13
  */
36
- type PatchObj<T extends Literal.Obj, P = T, R = T> = Patch.Update<T, P, R> | {
37
- [K in keyof T]?: PatchHelper<T[K], T, R>;
38
- };
14
+ type Entry<T, R> = Patch.Obj<T, R> | ((patchNested: Patch.Nested) => Patch.Obj<T, R>);
39
15
  /**
40
- * Type representing at least one Patch object for type T
41
- * @typeparam T - the target type
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
42
20
  */
43
- type Multi<T> = ArrayNonEmpty<Patch<T>>;
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>);
23
+ };
44
24
  /**
45
- * Type representing patches for values that are not objects or arrays
46
- * @typeparam T - the input type
47
- * @typeparam P - the parant type
48
- * @typeparam R - the root type
25
+ * A patch object can have as update either a new value or a nested patch object
26
+ * @typeparam T - the input value type
27
+ * @typeparam R - the root object type
49
28
  */
50
- type Update<T, P, R> = Literal.Value<T> | ((value: T, parent: P, root: R) => T extends boolean ? boolean : T);
29
+ type ObjItem<T, R> = T | NestedObj<T, R>;
51
30
  /**
52
- * Type representing allowed patches for arrays
53
- * @typeparam T - the array type
54
- * @typeparam P - the parent type
55
- * @typeparam R - the root type
31
+ * The function type to create a nested Patch object.
56
32
  */
57
- type PatchArray<T extends readonly unknown[], P, R> = (Patch.Update<T, P, R> | (T extends readonly (infer E)[] ? {
58
- [Patch.MAP]: PatchHelper<E, T, R>;
59
- } : never) | {
60
- [K in {
61
- [K2 in keyof T]: K2;
62
- }[keyof T]]?: PatchHelper<T[K], T, R>;
63
- }) & Literal.NoIterable;
33
+ type Nested = typeof patchNested;
64
34
  /**
65
- * Returns a function that patches a given object of type `T` with the given `patches`
66
- * Patch array.
67
- * @typeparam T - the value type to operate on
68
- * @typeparam T2 - the type the Patch is done for, should be equal to T
69
- * @param patches - the patches to apply to a given object
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.
70
39
  * @example
71
40
  * ```ts
72
- * const r = Patch.create<{ a: number, b: number }>({ b: v => v + 1 })({ a: 1, b: 2})
73
- * console.log(r)
74
- * // => { a: 1, b: 3 }
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' }]
75
44
  * ```
76
45
  */
77
- function create<T, T2 extends T = T>(...patches: Patch.Multi<T2>): (value: T) => T;
46
+ function create<T, Q extends T = T>(...patchItems: Patch<T & Q>[]): (value: Q & PlainObj<Q>) => Q;
78
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>[]);
51
+ }
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
+ * Returns an immutably updated version of the given `value` where the given `patchItems` have been
68
+ * applied to the result.
69
+ * @param value - the input value to patch
70
+ * @param patchItems - the `Patch` objects to apply to the input value
71
+ * @example
72
+ * ```ts
73
+ * 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 }) }) )
76
+ * // => { a: 1, b: { c: false, d: 'a' } }
77
+ * patch(input: ($) => ({ a: v => v + 1, b: $({ d: 'q' }) }) )
78
+ * // => { a: 2, b: { c: true, d: 'q' } }
79
+ * ```
80
+ */
81
+ export declare function patch<T>(value: T & PlainObj<T>, ...patchItems: Patch<T>[]): T;
79
82
  export {};
@@ -1,4 +1,5 @@
1
- import { Literal, Patch } from './internal';
1
+ import type { Update } from '@rimbu/common';
2
+ import type { IsPlainObj, PlainObj } from '@rimbu/base';
2
3
  /**
3
4
  * A string representing a path into an (nested) object of type T.
4
5
  * @typeparam T - the object type to select in
@@ -7,7 +8,7 @@ import { Literal, Patch } from './internal';
7
8
  * const p: Path<{ a: { b: { c : 5 }}}> = 'a.b'
8
9
  * ```
9
10
  */
10
- export declare type Path<T> = T extends Literal.Obj ? {
11
+ export declare type Path<T> = IsPlainObj<T> extends true ? {
11
12
  [K in string & keyof T]: `${K}` | `${K}.${Path<T[K]>}`;
12
13
  }[string & keyof T] : never;
13
14
  export declare namespace Path {
@@ -30,13 +31,13 @@ export declare namespace Path {
30
31
  * @param path - the path into the object
31
32
  * @example
32
33
  * ```ts
33
- * console.log(Path.getValue({ a: { b: { c: 5 } } }), 'a.b')
34
+ * console.log(Path.get({ a: { b: { c: 5 } } }), 'a.b')
34
35
  * // => { c: 5 }
35
- * console.log(Path.getValue({ a: { b: { c: 5 } } }), 'a.b.c')
36
+ * console.log(Path.get({ a: { b: { c: 5 } } }), 'a.b.c')
36
37
  * // => 5
37
38
  * ```
38
39
  */
39
- function getValue<T, P extends Path<T> = Path<T>>(source: T, path: P): Path.Result<T, P>;
40
+ function get<T, P extends Path<T> = Path<T>>(source: T & PlainObj<T>, path: P): Path.Result<T, P>;
40
41
  /**
41
42
  * Sets the value at the given path in the source to the given value.
42
43
  * @param source - the object to update
@@ -44,21 +45,9 @@ export declare namespace Path {
44
45
  * @param value - the new value to set at the given position
45
46
  * @example
46
47
  * ```ts
47
- * console.log(Path.setValue({ a: { b: { c: 5 } } }))
48
+ * console.log(Path.update({ a: { b: { c: 5 } } }, 'a.b.c', v => v + 5)
49
+ * // => { a: { b: { c: 6 } } }
48
50
  * ```
49
51
  */
50
- function setValue<T, P extends Path<T> = Path<T>>(source: T, path: P, value: Path.Result<T, P>): T;
51
- /**
52
- * Patches the value at the given path in the source to the given value using the given
53
- * `patches`.
54
- * @param source - the object to update
55
- * @param path - the path in the object to update
56
- * @param patches - one or more patches to update the value at the given path
57
- * @example
58
- * ```ts
59
- * console.log(Path.setValue({ a: { b: { c: 5 } } }, 'a.b.c', 8)
60
- * // => { a: { b: { c: 8 } } }
61
- * ```
62
- */
63
- function patchValue<T, P extends Path<T> = Path<T>>(source: T, path: P, ...patches: Patch.Multi<Path.Result<T, P>>): T;
52
+ function update<T, P extends Path<T> = Path<T>>(source: T & PlainObj<T>, path: P, value: Update<Path.Result<T, P>>): T;
64
53
  }
@@ -0,0 +1,13 @@
1
+ import type { IsPlainObj } from '@rimbu/base';
2
+ /**
3
+ * A deep readonly typed version of given type T. Makes all properties or elements read only.
4
+ * @typeparam T - the input type
5
+ */
6
+ export declare type Protected<T> = T extends readonly (infer E)[] ? readonly Protected<E>[] : T extends Map<infer K, infer V> ? Map<Protected<K>, Protected<V>> : T extends Set<infer E> ? Set<Protected<E>> : T extends Promise<infer E> ? Promise<Protected<E>> : IsPlainObj<T> extends true ? {
7
+ readonly [K in keyof T]: Protected<T[K]>;
8
+ } : T;
9
+ /**
10
+ * Returns the same value wrapped in the Protected type
11
+ * @param value - the value to wrap
12
+ */
13
+ export declare function Protected<T>(value: T): Protected<T>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rimbu/deep",
3
- "version": "0.9.2",
3
+ "version": "0.10.0",
4
4
  "description": "Tools to use handle plain JS objects as immutable objects",
5
5
  "keywords": [
6
6
  "immutable",
@@ -57,8 +57,8 @@
57
57
  },
58
58
  "sideEffects": false,
59
59
  "dependencies": {
60
- "@rimbu/base": "^0.8.2",
61
- "@rimbu/common": "^0.9.2",
60
+ "@rimbu/base": "^0.9.0",
61
+ "@rimbu/common": "^0.9.3",
62
62
  "tslib": "^2.4.0"
63
63
  },
64
64
  "publishConfig": {
@@ -68,5 +68,5 @@
68
68
  "index": "src/index.ts",
69
69
  "replacer": "../../config/denoify-rimbu-replacer.js"
70
70
  },
71
- "gitHead": "33dd7ca935f19f513586834a2ce1b1f886352ae7"
71
+ "gitHead": "4efaf8c469d606381517984436383fd6b1b61ec0"
72
72
  }
package/src/index.ts CHANGED
@@ -1,9 +1,19 @@
1
1
  /**
2
2
  * @packageDocumentation
3
3
  *
4
- * The `@rimbu/deep` package provides utilities to patch and match plain JavaScript objects..<br/>
4
+ * The `@rimbu/deep` package provides utilities to patch and match plain JavaScript objects.<br/>
5
5
  * <br/>
6
6
  * See the [Rimbu docs Deep overview page](/docs/deep/overview) for more information.
7
7
  */
8
8
 
9
- export * from './internal';
9
+ export {
10
+ patch,
11
+ patchNested,
12
+ Patch,
13
+ match,
14
+ Match,
15
+ Path,
16
+ Protected,
17
+ } from './internal';
18
+
19
+ export { Tuple } from './tuple';
package/src/internal.ts CHANGED
@@ -1,6 +1,5 @@
1
- export * from './tuple';
2
- export * from './literal';
3
- export * from './immutable';
1
+ export * from './protected';
2
+
4
3
  export * from './match';
5
- export * from './path';
6
4
  export * from './patch';
5
+ export * from './path';