maraj 2.6.0 → 2.7.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.
package/README.md CHANGED
@@ -5,19 +5,19 @@ A fast lightweight utility for creating **immutable updates**. Fully typed. Only
5
5
 
6
6
  ### Features
7
7
 
8
- - updateImmutably and modifyImmutably.
8
+ - Update and ExtendableUpdate.
9
+ - Usefull utilities like "remove", "select".
9
10
  - Full typescript support.
10
11
  - Correct type inference.
11
12
  - Multiple and concurrent updates.
12
- - Functional updates.
13
- - Includes usefull utilities like "remove", "select".
13
+ - Nested functional updates.
14
14
 
15
- **<u>_For Typescript:_</u>** in tsconfig.json set **"strictNullChecks"** and **"noUncheckedIndexedAccess"** to **true** to be able to infer correctly the type of optional properties and properties with posible undefined value. ({key?: ''} !== {key: '' | undefined})
15
+ <u>**For Typescript:**</u> in tsconfig.json set **"strictNullChecks"** and **"noUncheckedIndexedAccess"** to **true** to be able to infer correctly the type of *optional properties* and *properties with posible undefined value*. ( { key?: ... } is not equal to { key: ... | undefined } )
16
16
 
17
17
  ```ts
18
18
  const originalValue = { name: 'one', lastname: 'two' modified: false, files: [{ filename: 'one' }] }
19
19
 
20
- const updatedValue = updateImmutably(orignalValue, {
20
+ const updatedValue = update(orignalValue, {
21
21
  'name': 'updated',
22
22
  'modified': (value, fullObject) => !value,
23
23
  'files.0.filename': 'zero',
@@ -25,7 +25,7 @@ const updatedValue = updateImmutably(orignalValue, {
25
25
  // updatedValue = { name: 'updated', lastname: 'two' modified: true, files: [{ filename: 'zero' }] }
26
26
  originalValue.files[1] === updatedValue.files[1] // true
27
27
 
28
- const newValue = modifyImmutably(orignalValue, {
28
+ const newValue = extendableUpdate(orignalValue, {
29
29
  'newProp': 'new',
30
30
  'data.0.name': 'dataName'
31
31
  })
@@ -35,23 +35,29 @@ originalValue.files[1] === newValue.files[1] // true
35
35
 
36
36
  ### Limitations
37
37
 
38
- - In "modifyImmutably", **numbers** inside path will **always** create an **array** if the array/object doesnt exist beforehand. If you want an object instead of an array, add it beforehand.
38
+ - Can work with keys containing dots ({ "this.is.dotted.key": 123 }), however those keys (keys containing dots) must exist in the object beforehand (hasOwnProperty) and also must have a non-literal-object/array value to behave properly; like primitives, sets, maps, and so on. For example the path "a.b.c.d" will work properly in the following scenarios:
39
+ - { "a.b.c.d": ... }
40
+ - { a: { "b.c.d": ... } }
41
+ - { a: { b: {"c.d": ... } } }
42
+ - { a: { b: {"c": { d: ... } } } }
43
+
44
+ - In "extendableUpdate", **numbers** inside path will **always** create a mutable **array** if the array/object doesnt exist beforehand. If you want an object/tuple/readonlyArray instead of an array, add it beforehand as type.
39
45
 
40
46
  ```ts
41
- const updatedValue = modifyImmutably({}, {
47
+ const updatedValue = extendableUpdate({}, {
42
48
  'files.1.name': 'new name',
43
49
  })
44
50
  // The "files" prop is an array. updatedValue = { files: [<empty>, { name: 'new name' }] }
45
51
 
46
52
  // To get an object instead of an array create an object beforehand
47
- const updatedValue2 = modifyImmutably({}, {
53
+ const updatedValue2 = extendableUpdate({}, {
48
54
  'files': {}, // add an object first, so then i can add props as numbers after it
49
55
  'files.1.name': 'new name',
50
56
  })
51
57
  // updatedValue2 = { files: { '1': { name: 'new name' } } }
52
58
  ```
53
59
 
54
- - The type "UpdateDotPathObject" (the type used as second parameter in the updateImmutably function) if used to create new update objects using computed properties { [key]: value } will always throw a ts error even if the typing is correct. [Playground simple explanation](https://www.typescriptlang.org/play?ts=5.3.2#code/LAKALgngDgpgBAGQJYGcxwLxwOQENtwA+cABgCQDeAdgK4C2ARjAE4C+JooksiqYASjADGAe2YATTHApwA2gGk4SKrzQBdAPwAuOItacQoqmjhDmMXGBiDREqQB4AKnBgAPK1XEpVYAHwAKAGsYCB1HAEpMX2lQODijE3MhHWQ0GzFJLApYuNyAejy4AD0wbxZmMR0UZSF4ADcAFgA6AGYmgFYldAB3JAAbPrgwAAsK7rhcFXKxCfQhYeFA5QBzUxE6KBorSWCIb0nJOtw+mhhvGmqqVasNvst4PqQrZmOyupgVJAAzIYWh6BWSm8tiSYByuTkuzUOl24P0IFy5jANGYKiSoFYQA)
60
+ - The type "UpdateDotPathObject" (the type of the object provided containing the updates, the one used as second parameter in the update function) if used to create new update objects using computed properties { [key]: value } (middlewares for example) will always throw a ts error even if the typing is correct. [Playground simple explanation](https://www.typescriptlang.org/play?ts=5.3.2#code/LAKALgngDgpgBAGQJYGcxwLxwOQENtwA+cABgCQDeAdgK4C2ARjAE4C+JooksiqYASjADGAe2YATTHApwA2gGk4SKrzQBdAPwAuOItacQoqmjhDmMXGBiDREqQB4AKnBgAPK1XEpVYAHwAKAGsYCB1HAEpMX2lQODijE3MhHWQ0GzFJLApYuNyAejy4AD0wbxZmMR0UZSF4ADcAFgA6AGYmgFYldAB3JAAbPrgwAAsK7rhcFXKxCfQhYeFA5QBzUxE6KBorSWCIb0nJOtw+mhhvGmqqVasNvst4PqQrZmOyupgVJAAzIYWh6BWSm8tiSYByuTkuzUOl24P0IFy5jANGYKiSoFYQA)
55
61
 
56
62
  ```ts
57
63
  const updateFieldStore = <TPath extends DotPaths<Store>>(
@@ -69,7 +75,7 @@ const updateFieldStore = <TPath extends DotPaths<Store>>(
69
75
  - Use the "set" utility if typescript doesn't infer properly _"an optional field"_ vs a _"field which can have 'undefined' as type"_. Usually happens in optional nested props inside arrays.
70
76
 
71
77
  ```ts
72
- const updatedValue = updateImmutably(data, {
78
+ const updatedValue = update(data, {
73
79
  'files.0.nonOptionalProperty': 'new name',
74
80
  'files.1.nonOptionalProperty': undefined, //no ts error
75
81
  'files.0.nonOptionalProperty': set('new name'),
@@ -83,11 +89,15 @@ Arguments:
83
89
 
84
90
  - Original Object
85
91
  - Update Object
92
+ - Options (to change JS behaviour on non existing props and indexes)
93
+ - 'add': Adds non existing property/index.
94
+ - 'skip': Skips the update in the non-existing prop/index and still applies the rest of the possible updates.
95
+ - 'throw': Throws a JS error, usefull working with indexes making sure there are no "empty" indexes created if a new index is added which is bigger than the length of the current array.
86
96
 
87
97
  ## Example
88
98
 
89
99
  ```js
90
- import { updateImmutably } from "maraj";
100
+ import { update } from "maraj";
91
101
 
92
102
  const data = {
93
103
  profile: { name: "Lukasz" },
@@ -98,7 +108,7 @@ const data = {
98
108
  ]
99
109
  }
100
110
 
101
- const newUpdatedObject = updateImmutably(data, {
111
+ const newUpdatedObject = update(data, {
102
112
  "profile.name": "Lucas", //update values
103
113
  "works.1": "gs", //nested array update
104
114
  "history.1.available": (currentValue) => (!currentValue), //functional update
@@ -116,7 +126,7 @@ Arguments:
116
126
  ## Example
117
127
 
118
128
  ```js
119
- import { modifyImmutably } from "maraj";
129
+ import { extendableUpdate } from "maraj";
120
130
 
121
131
  const data = {
122
132
  profile: { name: "Lukasz" },
@@ -127,7 +137,7 @@ const data = {
127
137
  ]
128
138
  }
129
139
 
130
- const newUpdatedObject = modifyImmutably(data, {
140
+ const newUpdatedObject = extendableUpdate(data, {
131
141
  "profile.age": 28, //add new property
132
142
  "profile.name": "Lucas", //update values
133
143
  "works.10": "gs", //increases the array (filling it up with empty/undefined) and sets the value in the index of 10 to "gs"
@@ -136,12 +146,12 @@ const newUpdatedObject = modifyImmutably(data, {
136
146
 
137
147
  ## Remove Utility
138
148
 
139
- Removes the **key of an object** or the **index of an array** in the key provided in the **updateImmutably.**
149
+ Removes the **key of an object** or the **index of an array** in the key provided in the **update.**
140
150
 
141
151
  ```js
142
152
  import {remove} from 'maraj'
143
153
 
144
- const newUpdatedObject = updateImmutably(person,{
154
+ const newUpdatedObject = update(person,{
145
155
  'profile': (value) => remove(value, 'name'), // returns new value without the "name" prop
146
156
  'profile': (value) => remove(value, ['name', 'lastname']), // returns new value without the "name" and "lastname" prop
147
157
  'works': (value) => remove(value, 1), // returns new array without the provided index (1)
@@ -185,7 +195,7 @@ const [remainingPath, lastKey] = splitPathAtLastKey(stringPath)
185
195
  In some unusual cases (usually when updating an optional object prop inside an array) typescript infers incorrectly the optional key vs a key with undefined value. To fix this typing issue, use the "set" function so it correctly infers the type in the field.
186
196
 
187
197
  ```ts
188
- const updatedValue = updateImmutably(data, {
198
+ const updatedValue = update(data, {
189
199
  'files.0.optionalProperty': 'new name',
190
200
  'files.1.optionalProperty': undefined, //no ts error
191
201
  'files.0.optionalProperty': set('new name'),
package/dist/index.d.mts CHANGED
@@ -15,13 +15,12 @@ declare const remove: Remove;
15
15
  /** Index literal type to improve DX at managing updates. */
16
16
  declare const LITERAL_INDEX = "${number}";
17
17
  type LiteralIndex = typeof LITERAL_INDEX;
18
- type ObjectOrArray = Record<string | number | symbol, any>;
19
18
  type OptionValues = 'error' | 'skip' | 'add';
20
19
  type Options = {
21
20
  onNewProps?: OptionValues;
22
21
  onNewIndexes?: OptionValues;
23
22
  };
24
- type ImmutableUpdate = <TObject extends ObjectOrArray>(state: TObject, dotPathUpdateObject: DotPathUpdateObject<TObject>, options?: Options) => TObject;
23
+ type ImmutableUpdate = <TObject extends Record<PropertyKey, any>>(state: TObject, dotPathUpdateObject: UpdateObject<TObject>, options?: Options) => TObject;
25
24
  /**
26
25
  * Creates a new object applying immutable updates using dot-path syntax.
27
26
  * Can add or skip new props or indexes depending on options.
@@ -32,7 +31,7 @@ type ImmutableUpdate = <TObject extends ObjectOrArray>(state: TObject, dotPathUp
32
31
  * @returns New Updated Object.
33
32
  */
34
33
  declare const update: ImmutableUpdate;
35
- type ExtendableImmutableUpdate = <TObject extends ObjectOrArray, TUpdateObject extends DotPathUpdateObject<TObject>>(state: TObject, dotPathUpdateObject: TUpdateObject) => ExtendedUpdate<TObject, TUpdateObject>;
34
+ type ExtendableImmutableUpdate = <TObject extends Record<PropertyKey, any>, TUpdateObject extends UpdateObject<TObject>>(state: TObject, dotPathUpdateObject: TUpdateObject) => ExtendedUpdate<TObject, TUpdateObject>;
36
35
  /**
37
36
  * Creates a new object applying immutable updates using dot-path syntax.
38
37
  * It will always add non-existent props or indexes if provided.
@@ -63,8 +62,8 @@ type IsTuple<T extends ReadonlyArray<any>> = number extends T['length'] ? false
63
62
  type ArrayPaths<TInnerType, TAllowedTypes> = TInnerType extends TAllowedTypes ? TInnerType extends PrimitivesAndNativeObjects ? number | `${ArrayIndexes}` : number | `${ArrayIndexes}` | `${ArrayIndexes}.${DotPaths<TInnerType, TAllowedTypes>}` : `${ArrayIndexes}.${DotPaths<TInnerType, TAllowedTypes>}`;
64
63
  /** Dot-paths of an object. */
65
64
  type ObjectPaths<T, TAllowedTypes> = {
66
- [Key in keyof T & string]: T[Key] extends TAllowedTypes ? T[Key] extends PrimitivesAndNativeObjects ? `${Key}` : `${Key}` | `${Key}.${DotPaths<T[Key], TAllowedTypes>}` : `${Key}.${DotPaths<T[Key], TAllowedTypes>}`;
67
- }[keyof T & string];
65
+ [Key in keyof T & (string | number)]: T[Key] extends TAllowedTypes ? T[Key] extends PrimitivesAndNativeObjects ? `${Key}` : `${Key}` | `${Key}.${DotPaths<T[Key], TAllowedTypes>}` : `${Key}.${DotPaths<T[Key], TAllowedTypes>}`;
66
+ }[keyof T & (string | number)];
68
67
  /** Dot-paths of a tuple. */
69
68
  type TuplePaths<T, TAllowedTypes> = ObjectPaths<Omit<T, keyof any[]>, TAllowedTypes>;
70
69
  /** Literal union of all posible dot-paths which satisfy provided types as second argument (default: any). */
@@ -75,28 +74,24 @@ type DotPaths<T, TAllowedTypes = any> = T extends ReadonlyArray<infer U> ? IsTup
75
74
  * --------------------------------------------
76
75
  */
77
76
  /** Nested type implementation. */
78
- type NestedType<TObject, TPath> = TPath extends '' ? TObject : TPath extends keyof TObject ? TObject[TPath] : TPath extends LiteralIndex ? never : TPath extends `${number}` ? TObject extends ReadonlyArray<infer U> ? U : never : TPath extends `${infer K}.${infer R}` ? K extends keyof TObject ? NestedType<TObject[K], R> : K extends LiteralIndex ? never : K extends `${number}` ? TObject extends ReadonlyArray<infer U> ? NestedType<U, R> : never : never : never;
79
- /** Value of a nested property of a given dot-path. */
80
- type ExactValueInDotPath<TObject, TPath extends DotPaths<TObject> | ''> = NestedType<TObject, TPath>;
77
+ type ValueInPath<TObject, TPath> = TPath extends keyof TObject ? TObject[TPath] : TPath extends '' ? TObject : TPath extends LiteralIndex ? never : TPath extends `${number}` ? TObject extends ReadonlyArray<infer U> ? U : never : TPath extends `${infer K}.${infer R}` ? K extends keyof TObject ? ValueInPath<TObject[K], R> : K extends LiteralIndex ? never : K extends `${number}` ? TObject extends ReadonlyArray<infer U> ? ValueInPath<U, R> : never : never : never;
81
78
  /**
82
79
  * --------------------------------------------
83
80
  * RETURNED VALUE OF A NESTED PROPERTY PROVIDING A DOT PATH
84
81
  * --------------------------------------------
85
82
  */
86
83
  /** Returned nested type implementation. */
87
- type ReturnedNestedValue<TObject, TPath> = TPath extends '' ? TObject : TPath extends keyof TObject ? TObject[TPath] : TPath extends LiteralIndex ? never : TPath extends `${number}` ? TObject extends ReadonlyArray<infer U> ? (U | undefined) : never : TPath extends `${infer K}.${infer R}` ? K extends keyof TObject ? ReturnedNestedValue<TObject[K], R> : K extends LiteralIndex ? never : K extends `${number}` ? TObject extends ReadonlyArray<infer U> ? (ReturnedNestedValue<U, R> | undefined) : never : never : never;
88
- /** Value of a RETURNED nested property of a given dot-path (so when accessing arrays can be undefined). */
89
- type ReturnedValueInDotPath<TObject, TPath extends DotPaths<TObject> | ''> = ReturnedNestedValue<TObject, TPath>;
84
+ type ReturnedValueInPath<TObject, TPath> = TPath extends '' ? TObject : TPath extends keyof TObject ? TPath extends number ? TObject extends ReadonlyArray<infer U> ? (U | undefined) : TObject[TPath] : TObject[TPath] : TPath extends `${number}` ? TObject extends ReadonlyArray<infer U> ? (U | undefined) : never : TPath extends LiteralIndex ? never : TPath extends `${infer K}.${infer R}` ? K extends keyof TObject ? ReturnedValueInPath<TObject[K], R> : K extends LiteralIndex ? never : K extends `${number}` ? TObject extends ReadonlyArray<infer U> ? (ReturnedValueInPath<U, R> | undefined) : never : never : never;
90
85
  /**
91
86
  * --------------------------------------------
92
87
  * UPDATE OBJECT WITH DOT PATH IMPLEMENTATION
93
88
  * --------------------------------------------
94
89
  */
95
90
  /** Value of a dot-path update object, can be the value or a function. */
96
- type DotPathUpdateValue<TObject, TPath extends DotPaths<TObject>> = ExactValueInDotPath<TObject, TPath> | ((fieldValue: ExactValueInDotPath<TObject, TPath>) => ExactValueInDotPath<TObject, TPath>);
91
+ type UpdateValue<TObject, TPath> = ValueInPath<TObject, TPath> | ((fieldValue: ValueInPath<TObject, TPath>) => ValueInPath<TObject, TPath>);
97
92
  /** Dot-path update object, used to give updates to the updateImmutably function. */
98
- type DotPathUpdateObject<TObject> = {
99
- [TPath in DotPaths<TObject>]?: ExactValueInDotPath<TObject, TPath> | ((fieldValue: ExactValueInDotPath<TObject, TPath>) => ExactValueInDotPath<TObject, TPath>);
93
+ type UpdateObject<TObject, TPaths extends PropertyKey = DotPaths<TObject>> = {
94
+ [TPath in TPaths]?: ValueInPath<TObject, TPath> | ((fieldValue: ValueInPath<TObject, TPath>) => ValueInPath<TObject, TPath>);
100
95
  };
101
96
  /**
102
97
  * --------------------------------------------
@@ -139,7 +134,10 @@ type ExtractTypeFromDotPathUpdateObject<T extends Record<string, any>> = T exten
139
134
  /** New expanded value after aplying updates including new properties */
140
135
  type ExtendedUpdate<TObject extends Record<string | number | symbol, any>, TDotPathUpdateObject extends Record<string | number | symbol, any>> = TObject extends Array<infer U> ? ExtractTypeFromDotPathUpdateObject<TDotPathUpdateObject> extends Array<infer W> ? Array<U | W> : TObject & ExtractTypeFromDotPathUpdateObject<TDotPathUpdateObject> : ExtractTypeFromDotPathUpdateObject<TObject & TDotPathUpdateObject>;
141
136
 
142
- type Select = <TObject, TPath extends DotPaths<TObject> | ''>(state: TObject, path: TPath) => ReturnedValueInDotPath<TObject, TPath>;
137
+ type Select = {
138
+ <T, TPath extends DotPaths<T>>(state: T, path: TPath): ReturnedValueInPath<T, TPath>;
139
+ <T, TPath extends ''>(state: T, path: TPath): T;
140
+ };
143
141
  /**
144
142
  * Returns the value from a given dot path of an object/array or undefined if doesn't exist.
145
143
  * @param state State from which retrieve the value.
@@ -172,4 +170,4 @@ declare const isObjectLiteral: (valueToTest: any) => boolean;
172
170
  declare const parseStringIndex: (v: string) => number | null;
173
171
  declare const isStringIndex: (v: string) => boolean;
174
172
 
175
- export { type DotPathUpdateObject, type DotPathUpdateValue, type DotPaths, type ExactValueInDotPath, type LiteralIndex, type ReturnedValueInDotPath, extendableUpdate, isObjectLiteral, isStringIndex, parseStringIndex, remove, select, set, splitPathAtLastKey, update };
173
+ export { type DotPaths, type LiteralIndex, type ReturnedValueInPath, type UpdateObject, type UpdateValue, type ValueInPath, extendableUpdate, isObjectLiteral, isStringIndex, parseStringIndex, remove, select, set, splitPathAtLastKey, update };
package/dist/index.d.ts CHANGED
@@ -15,13 +15,12 @@ declare const remove: Remove;
15
15
  /** Index literal type to improve DX at managing updates. */
16
16
  declare const LITERAL_INDEX = "${number}";
17
17
  type LiteralIndex = typeof LITERAL_INDEX;
18
- type ObjectOrArray = Record<string | number | symbol, any>;
19
18
  type OptionValues = 'error' | 'skip' | 'add';
20
19
  type Options = {
21
20
  onNewProps?: OptionValues;
22
21
  onNewIndexes?: OptionValues;
23
22
  };
24
- type ImmutableUpdate = <TObject extends ObjectOrArray>(state: TObject, dotPathUpdateObject: DotPathUpdateObject<TObject>, options?: Options) => TObject;
23
+ type ImmutableUpdate = <TObject extends Record<PropertyKey, any>>(state: TObject, dotPathUpdateObject: UpdateObject<TObject>, options?: Options) => TObject;
25
24
  /**
26
25
  * Creates a new object applying immutable updates using dot-path syntax.
27
26
  * Can add or skip new props or indexes depending on options.
@@ -32,7 +31,7 @@ type ImmutableUpdate = <TObject extends ObjectOrArray>(state: TObject, dotPathUp
32
31
  * @returns New Updated Object.
33
32
  */
34
33
  declare const update: ImmutableUpdate;
35
- type ExtendableImmutableUpdate = <TObject extends ObjectOrArray, TUpdateObject extends DotPathUpdateObject<TObject>>(state: TObject, dotPathUpdateObject: TUpdateObject) => ExtendedUpdate<TObject, TUpdateObject>;
34
+ type ExtendableImmutableUpdate = <TObject extends Record<PropertyKey, any>, TUpdateObject extends UpdateObject<TObject>>(state: TObject, dotPathUpdateObject: TUpdateObject) => ExtendedUpdate<TObject, TUpdateObject>;
36
35
  /**
37
36
  * Creates a new object applying immutable updates using dot-path syntax.
38
37
  * It will always add non-existent props or indexes if provided.
@@ -63,8 +62,8 @@ type IsTuple<T extends ReadonlyArray<any>> = number extends T['length'] ? false
63
62
  type ArrayPaths<TInnerType, TAllowedTypes> = TInnerType extends TAllowedTypes ? TInnerType extends PrimitivesAndNativeObjects ? number | `${ArrayIndexes}` : number | `${ArrayIndexes}` | `${ArrayIndexes}.${DotPaths<TInnerType, TAllowedTypes>}` : `${ArrayIndexes}.${DotPaths<TInnerType, TAllowedTypes>}`;
64
63
  /** Dot-paths of an object. */
65
64
  type ObjectPaths<T, TAllowedTypes> = {
66
- [Key in keyof T & string]: T[Key] extends TAllowedTypes ? T[Key] extends PrimitivesAndNativeObjects ? `${Key}` : `${Key}` | `${Key}.${DotPaths<T[Key], TAllowedTypes>}` : `${Key}.${DotPaths<T[Key], TAllowedTypes>}`;
67
- }[keyof T & string];
65
+ [Key in keyof T & (string | number)]: T[Key] extends TAllowedTypes ? T[Key] extends PrimitivesAndNativeObjects ? `${Key}` : `${Key}` | `${Key}.${DotPaths<T[Key], TAllowedTypes>}` : `${Key}.${DotPaths<T[Key], TAllowedTypes>}`;
66
+ }[keyof T & (string | number)];
68
67
  /** Dot-paths of a tuple. */
69
68
  type TuplePaths<T, TAllowedTypes> = ObjectPaths<Omit<T, keyof any[]>, TAllowedTypes>;
70
69
  /** Literal union of all posible dot-paths which satisfy provided types as second argument (default: any). */
@@ -75,28 +74,24 @@ type DotPaths<T, TAllowedTypes = any> = T extends ReadonlyArray<infer U> ? IsTup
75
74
  * --------------------------------------------
76
75
  */
77
76
  /** Nested type implementation. */
78
- type NestedType<TObject, TPath> = TPath extends '' ? TObject : TPath extends keyof TObject ? TObject[TPath] : TPath extends LiteralIndex ? never : TPath extends `${number}` ? TObject extends ReadonlyArray<infer U> ? U : never : TPath extends `${infer K}.${infer R}` ? K extends keyof TObject ? NestedType<TObject[K], R> : K extends LiteralIndex ? never : K extends `${number}` ? TObject extends ReadonlyArray<infer U> ? NestedType<U, R> : never : never : never;
79
- /** Value of a nested property of a given dot-path. */
80
- type ExactValueInDotPath<TObject, TPath extends DotPaths<TObject> | ''> = NestedType<TObject, TPath>;
77
+ type ValueInPath<TObject, TPath> = TPath extends keyof TObject ? TObject[TPath] : TPath extends '' ? TObject : TPath extends LiteralIndex ? never : TPath extends `${number}` ? TObject extends ReadonlyArray<infer U> ? U : never : TPath extends `${infer K}.${infer R}` ? K extends keyof TObject ? ValueInPath<TObject[K], R> : K extends LiteralIndex ? never : K extends `${number}` ? TObject extends ReadonlyArray<infer U> ? ValueInPath<U, R> : never : never : never;
81
78
  /**
82
79
  * --------------------------------------------
83
80
  * RETURNED VALUE OF A NESTED PROPERTY PROVIDING A DOT PATH
84
81
  * --------------------------------------------
85
82
  */
86
83
  /** Returned nested type implementation. */
87
- type ReturnedNestedValue<TObject, TPath> = TPath extends '' ? TObject : TPath extends keyof TObject ? TObject[TPath] : TPath extends LiteralIndex ? never : TPath extends `${number}` ? TObject extends ReadonlyArray<infer U> ? (U | undefined) : never : TPath extends `${infer K}.${infer R}` ? K extends keyof TObject ? ReturnedNestedValue<TObject[K], R> : K extends LiteralIndex ? never : K extends `${number}` ? TObject extends ReadonlyArray<infer U> ? (ReturnedNestedValue<U, R> | undefined) : never : never : never;
88
- /** Value of a RETURNED nested property of a given dot-path (so when accessing arrays can be undefined). */
89
- type ReturnedValueInDotPath<TObject, TPath extends DotPaths<TObject> | ''> = ReturnedNestedValue<TObject, TPath>;
84
+ type ReturnedValueInPath<TObject, TPath> = TPath extends '' ? TObject : TPath extends keyof TObject ? TPath extends number ? TObject extends ReadonlyArray<infer U> ? (U | undefined) : TObject[TPath] : TObject[TPath] : TPath extends `${number}` ? TObject extends ReadonlyArray<infer U> ? (U | undefined) : never : TPath extends LiteralIndex ? never : TPath extends `${infer K}.${infer R}` ? K extends keyof TObject ? ReturnedValueInPath<TObject[K], R> : K extends LiteralIndex ? never : K extends `${number}` ? TObject extends ReadonlyArray<infer U> ? (ReturnedValueInPath<U, R> | undefined) : never : never : never;
90
85
  /**
91
86
  * --------------------------------------------
92
87
  * UPDATE OBJECT WITH DOT PATH IMPLEMENTATION
93
88
  * --------------------------------------------
94
89
  */
95
90
  /** Value of a dot-path update object, can be the value or a function. */
96
- type DotPathUpdateValue<TObject, TPath extends DotPaths<TObject>> = ExactValueInDotPath<TObject, TPath> | ((fieldValue: ExactValueInDotPath<TObject, TPath>) => ExactValueInDotPath<TObject, TPath>);
91
+ type UpdateValue<TObject, TPath> = ValueInPath<TObject, TPath> | ((fieldValue: ValueInPath<TObject, TPath>) => ValueInPath<TObject, TPath>);
97
92
  /** Dot-path update object, used to give updates to the updateImmutably function. */
98
- type DotPathUpdateObject<TObject> = {
99
- [TPath in DotPaths<TObject>]?: ExactValueInDotPath<TObject, TPath> | ((fieldValue: ExactValueInDotPath<TObject, TPath>) => ExactValueInDotPath<TObject, TPath>);
93
+ type UpdateObject<TObject, TPaths extends PropertyKey = DotPaths<TObject>> = {
94
+ [TPath in TPaths]?: ValueInPath<TObject, TPath> | ((fieldValue: ValueInPath<TObject, TPath>) => ValueInPath<TObject, TPath>);
100
95
  };
101
96
  /**
102
97
  * --------------------------------------------
@@ -139,7 +134,10 @@ type ExtractTypeFromDotPathUpdateObject<T extends Record<string, any>> = T exten
139
134
  /** New expanded value after aplying updates including new properties */
140
135
  type ExtendedUpdate<TObject extends Record<string | number | symbol, any>, TDotPathUpdateObject extends Record<string | number | symbol, any>> = TObject extends Array<infer U> ? ExtractTypeFromDotPathUpdateObject<TDotPathUpdateObject> extends Array<infer W> ? Array<U | W> : TObject & ExtractTypeFromDotPathUpdateObject<TDotPathUpdateObject> : ExtractTypeFromDotPathUpdateObject<TObject & TDotPathUpdateObject>;
141
136
 
142
- type Select = <TObject, TPath extends DotPaths<TObject> | ''>(state: TObject, path: TPath) => ReturnedValueInDotPath<TObject, TPath>;
137
+ type Select = {
138
+ <T, TPath extends DotPaths<T>>(state: T, path: TPath): ReturnedValueInPath<T, TPath>;
139
+ <T, TPath extends ''>(state: T, path: TPath): T;
140
+ };
143
141
  /**
144
142
  * Returns the value from a given dot path of an object/array or undefined if doesn't exist.
145
143
  * @param state State from which retrieve the value.
@@ -172,4 +170,4 @@ declare const isObjectLiteral: (valueToTest: any) => boolean;
172
170
  declare const parseStringIndex: (v: string) => number | null;
173
171
  declare const isStringIndex: (v: string) => boolean;
174
172
 
175
- export { type DotPathUpdateObject, type DotPathUpdateValue, type DotPaths, type ExactValueInDotPath, type LiteralIndex, type ReturnedValueInDotPath, extendableUpdate, isObjectLiteral, isStringIndex, parseStringIndex, remove, select, set, splitPathAtLastKey, update };
173
+ export { type DotPaths, type LiteralIndex, type ReturnedValueInPath, type UpdateObject, type UpdateValue, type ValueInPath, extendableUpdate, isObjectLiteral, isStringIndex, parseStringIndex, remove, select, set, splitPathAtLastKey, update };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var m=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var v=(e,t)=>{for(var r in t)m(e,r,{get:t[r],enumerable:!0})},C=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of R(t))!k.call(e,a)&&a!==r&&m(e,a,{get:()=>t[a],enumerable:!(n=$(t,a))||n.enumerable});return e};var W=e=>C(m({},"__esModule",{value:!0}),e);var q={};v(q,{extendableUpdate:()=>L,isObjectLiteral:()=>d,isStringIndex:()=>y,parseStringIndex:()=>K,remove:()=>j,select:()=>P,set:()=>w,splitPathAtLastKey:()=>A,update:()=>D});module.exports=W(q);var j=(e,t)=>{if(!Array.isArray(e)&&e?.constructor!==Object)throw'Wrong type provided in "remove" function';let r=Array.isArray(t)?t:[t];if(Array.isArray(e)){let a=Symbol(),l=[...e];return r.forEach(s=>{l[s]=a}),l.filter(s=>s!==a)}let n={...e};return r.forEach(a=>delete n[a]),n};var P=(e,t)=>!t||typeof t!="string"?e:t.split(".").reduce((r,n)=>{if(r?.hasOwnProperty(n))return r[n]},e);var A=e=>{if(typeof e!="string")throw new Error(`Wrong dotPath type: ${e}`);let t=e.lastIndexOf(".")+1,r=t?e.slice(0,t-1):"",n=e.slice(t);return[r,n]};var w=e=>()=>e;var d=e=>!!e&&Object.getPrototypeOf(e)===Object.prototype;var K=e=>{let t=parseInt(e);return t.toString()===e?t:null},y=e=>parseInt(e).toString()===e;var U=e=>JSON.stringify(e),O=(e,t)=>e.slice(0,t).join("."),g=e=>Array.isArray(e),E=(e,t,r={})=>{if(r={onNewProps:"add",onNewIndexes:"error",...r},!d(e)&&!Array.isArray(e))throw new Error(`"${U(e)}" is not an literalObject/array`);if(!d(t))throw new Error('wrong "updates" type provided');let n=Array.isArray(e)?[...e]:{...e},a={};for(let[l,f]of Object.entries(t)){if(!l)continue;let s=l.split("."),p=s.pop(),u=a,i=n;for(let c=0;c<s.length;c++){let o=s[c],x=i[o],S=d(x),h=g(x),T=x===void 0;if(!S&&!h&&!T)throw new Error(`Property "${o}" in "${O(s,c)}" is a primitive`);if(!u[o]){if(T){let V=g(i)&&y(o),N=y(s[c+1]??p),I=V?r.onNewIndexes:r.onNewProps;if(I==="error")throw new Error(`${o} doesn't exist in "${O(s,c)}"`);if(I==="skip")continue;i[o]=N?[]:{}}else i[o]=h?[...x]:{...x};u[o]={}}i=i[o],u=u[o]}let b=i;if(!b.hasOwnProperty(p)){let o=Array.isArray(b)&&y(p)?r.onNewIndexes:r.onNewProps;if(o==="error")throw new Error(`Property/Index "${p}" doesnt exist in the path "${O([...s,p])}". Its value is: "${U(b)}"`);if(o==="skip")continue}b[p]=typeof f=="function"?f(b[p]):f,delete u[p]}return n},D=(e,t,r)=>E(e,t,r),L=(e,t)=>E(e,t);0&&(module.exports={extendableUpdate,isObjectLiteral,isStringIndex,parseStringIndex,remove,select,set,splitPathAtLastKey,update});
1
+ "use strict";var m=Object.defineProperty;var R=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var v=(e,t)=>{for(var r in t)m(e,r,{get:t[r],enumerable:!0})},C=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of $(t))!k.call(e,o)&&o!==r&&m(e,o,{get:()=>t[o],enumerable:!(n=R(t,o))||n.enumerable});return e};var N=e=>C(m({},"__esModule",{value:!0}),e);var W={};v(W,{extendableUpdate:()=>L,isObjectLiteral:()=>d,isStringIndex:()=>y,parseStringIndex:()=>U,remove:()=>I,select:()=>j,set:()=>K,splitPathAtLastKey:()=>w,update:()=>E});module.exports=N(W);var I=(e,t)=>{if(!Array.isArray(e)&&e?.constructor!==Object)throw'Wrong type provided in "remove" function';let r=Array.isArray(t)?t:[t];if(Array.isArray(e)){let o=Symbol(),p=[...e];return r.forEach(s=>{p[s]=o}),p.filter(s=>s!==o)}let n={...e};return r.forEach(o=>delete n[o]),n};var j=(e,t)=>{if(typeof t!="string")throw new Error("path is not a string");if(!t)return e;let r=t.split("."),n=e;for(;r.length;){let o=r.join(".");if(n?.hasOwnProperty(o))return n[o];if(!n?.hasOwnProperty(r[0]))return;n=n[r[0]],r.shift()}return n};var w=e=>{if(typeof e!="string")throw new Error(`Wrong dotPath type: ${e}`);let t=e.lastIndexOf(".")+1,r=t?e.slice(0,t-1):"",n=e.slice(t);return[r,n]};var K=e=>()=>e;var d=e=>!!e&&Object.getPrototypeOf(e)===Object.prototype;var U=e=>{let t=parseInt(e);return t.toString()===e?t:null},y=e=>parseInt(e).toString()===e;var A=e=>JSON.stringify(e),h=e=>Array.isArray(e),g=(e,t,r={})=>{if(!d(e)&&!h(e))throw new Error(`"${A(e)}" is not an literalObject/array`);if(!d(t))throw new Error('wrong "updateObject" type provided');let n=Array.isArray(e)?[...e]:{...e},o={};for(let[p,x]of Object.entries(t)){if(p==="")continue;let s=p.split("."),l=o,i=n;for(;s.length>1;){let b=s.join(".");if(Object.hasOwn(i,b)){s=[b];break}let a=s[0],f=i[a],S=d(f),T=h(f),O=f===void 0;if(!S&&!T&&!O)throw new Error(`Property "${a}" in "${p}" is a primitive`);if(!l[a]){if(O){let V=h(i)&&y(a),D=y(s[1]),P=V?r.onNewIndexes:r.onNewProps;if(P==="error")throw new Error(`${a} doesn't exist in "${p}"`);if(P==="skip")continue;i[a]=D?[]:{}}else i[a]=T?[...f]:{...f};l[a]={}}i=i[a],l=l[a],s.shift()}let c=s[0],u=i;if(!Object.hasOwn(u,c)){let a=h(u)&&y(c)?r.onNewIndexes:r.onNewProps;if(a==="error")throw new Error(`Property/Index "${c}" doesnt exist in the path "${p}". Its value is: "${A(u)}"`);if(a==="skip")continue}u[c]=typeof x=="function"?x(u[c]):x,delete l[c]}return n},E=(e,t,r)=>g(e,t,r),L=(e,t)=>g(e,t);0&&(module.exports={extendableUpdate,isObjectLiteral,isStringIndex,parseStringIndex,remove,select,set,splitPathAtLastKey,update});
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- var U=(e,t)=>{if(!Array.isArray(e)&&e?.constructor!==Object)throw'Wrong type provided in "remove" function';let r=Array.isArray(t)?t:[t];if(Array.isArray(e)){let c=Symbol(),d=[...e];return r.forEach(o=>{d[o]=c}),d.filter(o=>o!==c)}let a={...e};return r.forEach(c=>delete a[c]),a};var g=(e,t)=>!t||typeof t!="string"?e:t.split(".").reduce((r,a)=>{if(r?.hasOwnProperty(a))return r[a]},e);var E=e=>{if(typeof e!="string")throw new Error(`Wrong dotPath type: ${e}`);let t=e.lastIndexOf(".")+1,r=t?e.slice(0,t-1):"",a=e.slice(t);return[r,a]};var D=e=>()=>e;var b=e=>!!e&&Object.getPrototypeOf(e)===Object.prototype;var L=e=>{let t=parseInt(e);return t.toString()===e?t:null},x=e=>parseInt(e).toString()===e;var I=e=>JSON.stringify(e),m=(e,t)=>e.slice(0,t).join("."),j=e=>Array.isArray(e),P=(e,t,r={})=>{if(r={onNewProps:"add",onNewIndexes:"error",...r},!b(e)&&!Array.isArray(e))throw new Error(`"${I(e)}" is not an literalObject/array`);if(!b(t))throw new Error('wrong "updates" type provided');let a=Array.isArray(e)?[...e]:{...e},c={};for(let[d,f]of Object.entries(t)){if(!d)continue;let o=d.split("."),s=o.pop(),y=c,p=a;for(let i=0;i<o.length;i++){let n=o[i],u=p[n],A=b(u),O=j(u),h=u===void 0;if(!A&&!O&&!h)throw new Error(`Property "${n}" in "${m(o,i)}" is a primitive`);if(!y[n]){if(h){let w=j(p)&&x(n),K=x(o[i+1]??s),T=w?r.onNewIndexes:r.onNewProps;if(T==="error")throw new Error(`${n} doesn't exist in "${m(o,i)}"`);if(T==="skip")continue;p[n]=K?[]:{}}else p[n]=O?[...u]:{...u};y[n]={}}p=p[n],y=y[n]}let l=p;if(!l.hasOwnProperty(s)){let n=Array.isArray(l)&&x(s)?r.onNewIndexes:r.onNewProps;if(n==="error")throw new Error(`Property/Index "${s}" doesnt exist in the path "${m([...o,s])}". Its value is: "${I(l)}"`);if(n==="skip")continue}l[s]=typeof f=="function"?f(l[s]):f,delete y[s]}return a},S=(e,t,r)=>P(e,t,r),V=(e,t)=>P(e,t);export{V as extendableUpdate,b as isObjectLiteral,x as isStringIndex,L as parseStringIndex,U as remove,g as select,D as set,E as splitPathAtLastKey,S as update};
1
+ var U=(e,t)=>{if(!Array.isArray(e)&&e?.constructor!==Object)throw'Wrong type provided in "remove" function';let r=Array.isArray(t)?t:[t];if(Array.isArray(e)){let s=Symbol(),p=[...e];return r.forEach(a=>{p[a]=s}),p.filter(a=>a!==s)}let n={...e};return r.forEach(s=>delete n[s]),n};var A=(e,t)=>{if(typeof t!="string")throw new Error("path is not a string");if(!t)return e;let r=t.split("."),n=e;for(;r.length;){let s=r.join(".");if(n?.hasOwnProperty(s))return n[s];if(!n?.hasOwnProperty(r[0]))return;n=n[r[0]],r.shift()}return n};var g=e=>{if(typeof e!="string")throw new Error(`Wrong dotPath type: ${e}`);let t=e.lastIndexOf(".")+1,r=t?e.slice(0,t-1):"",n=e.slice(t);return[r,n]};var E=e=>()=>e;var u=e=>!!e&&Object.getPrototypeOf(e)===Object.prototype;var L=e=>{let t=parseInt(e);return t.toString()===e?t:null},f=e=>parseInt(e).toString()===e;var P=e=>JSON.stringify(e),h=e=>Array.isArray(e),I=(e,t,r={})=>{if(!u(e)&&!h(e))throw new Error(`"${P(e)}" is not an literalObject/array`);if(!u(t))throw new Error('wrong "updateObject" type provided');let n=Array.isArray(e)?[...e]:{...e},s={};for(let[p,x]of Object.entries(t)){if(p==="")continue;let a=p.split("."),d=s,i=n;for(;a.length>1;){let b=a.join(".");if(Object.hasOwn(i,b)){a=[b];break}let o=a[0],l=i[o],j=u(l),m=h(l),T=l===void 0;if(!j&&!m&&!T)throw new Error(`Property "${o}" in "${p}" is a primitive`);if(!d[o]){if(T){let w=h(i)&&f(o),K=f(a[1]),O=w?r.onNewIndexes:r.onNewProps;if(O==="error")throw new Error(`${o} doesn't exist in "${p}"`);if(O==="skip")continue;i[o]=K?[]:{}}else i[o]=m?[...l]:{...l};d[o]={}}i=i[o],d=d[o],a.shift()}let c=a[0],y=i;if(!Object.hasOwn(y,c)){let o=h(y)&&f(c)?r.onNewIndexes:r.onNewProps;if(o==="error")throw new Error(`Property/Index "${c}" doesnt exist in the path "${p}". Its value is: "${P(y)}"`);if(o==="skip")continue}y[c]=typeof x=="function"?x(y[c]):x,delete d[c]}return n},S=(e,t,r)=>I(e,t,r),V=(e,t)=>I(e,t);export{V as extendableUpdate,u as isObjectLiteral,f as isStringIndex,L as parseStringIndex,U as remove,A as select,E as set,g as splitPathAtLastKey,S as update};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maraj",
3
- "version": "2.6.0",
3
+ "version": "2.7.1",
4
4
  "description": "A lightweight 600 bytes gzipped alternative for immutable updates while dealing with objects and arrays",
5
5
  "keywords": [
6
6
  "shallow",