maraj 2.10.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +178 -140
- package/dist/index.d.mts +54 -89
- package/dist/index.d.ts +54 -89
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -1,211 +1,249 @@
|
|
|
1
|
-
|
|
2
1
|
# Maraj
|
|
3
2
|
|
|
4
|
-
A
|
|
3
|
+
A small utility for **immutable updates** of objects and arrays with dot paths. Fully typed, about 1.2 KB gzipped. Includes helpers to work with updates (`remove`, `select`, `set`, ...).
|
|
5
4
|
|
|
6
5
|
### Features
|
|
7
6
|
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
7
|
+
- `update` with typed dot paths (`'files.0.name'`), checked by TypeScript.
|
|
8
|
+
- Several updates in one call, sharing the copies of common parents.
|
|
9
|
+
- Function updates that get the current value.
|
|
10
|
+
- Only the objects and arrays along each path are copied; everything else keeps its reference.
|
|
11
|
+
- Options to add, skip or throw on missing props and indexes.
|
|
12
|
+
- Helpers: `remove`, `select`, `set`, `splitPathAtLastKey` and a few type helpers.
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
```sh
|
|
15
|
+
npm install maraj
|
|
16
|
+
```
|
|
16
17
|
|
|
17
18
|
```ts
|
|
18
|
-
|
|
19
|
+
import { update } from 'maraj'
|
|
19
20
|
|
|
20
|
-
const
|
|
21
|
+
const original = { name: 'one', lastname: 'two', modified: false, files: [{ filename: 'one' }, { filename: 'two' }] }
|
|
22
|
+
|
|
23
|
+
const updated = update(original, {
|
|
21
24
|
'name': 'updated',
|
|
22
|
-
'modified': (value
|
|
25
|
+
'modified': (value) => !value,
|
|
23
26
|
'files.0.filename': 'zero',
|
|
24
27
|
})
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const newValue = extendableUpdate(orignalValue, {
|
|
29
|
-
'newProp': 'new',
|
|
30
|
-
'data.0.name': 'dataName'
|
|
31
|
-
})
|
|
32
|
-
// updatedValue = { ... , newProp: 'new', data: [{ name: 'dataName' }] }
|
|
33
|
-
originalValue.files[1] === newValue.files[1] // true
|
|
28
|
+
// updated = { name: 'updated', lastname: 'two', modified: true, files: [{ filename: 'zero' }, { filename: 'two' }] }
|
|
29
|
+
original.files[1] === updated.files[1] // true, not copied
|
|
30
|
+
original.files === updated.files // false, copied because 'files.0' changed
|
|
34
31
|
```
|
|
35
32
|
|
|
36
|
-
|
|
33
|
+
<u>**For TypeScript:**</u> set **"strictNullChecks"** and **"noUncheckedIndexedAccess"** to **true** in tsconfig.json, so optional props and props that can be `undefined` get the right type (`{ key?: string }` is not the same as `{ key: string | undefined }`). With **"exactOptionalPropertyTypes"** too, setting `undefined` on a prop that isn't optional is an error.
|
|
34
|
+
|
|
35
|
+
## update
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
update(state, updateObject, options?)
|
|
39
|
+
```
|
|
37
40
|
|
|
38
|
-
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
- { a: { b: {"c.d": ... } } }
|
|
42
|
-
- { a: { b: {"c": { d: ... } } } }
|
|
41
|
+
- `state`: an object literal or array, anything else throws (`Date`, `Map`, class instances, `null`).
|
|
42
|
+
- `updateObject`: an object literal of `{ 'dot.path': newValue }`, applied in order.
|
|
43
|
+
- `options`: what to do with paths that don't exist yet (see [Options](#options)).
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
Returns a new object with the updates; `state` is never changed.
|
|
45
46
|
|
|
46
|
-
-
|
|
47
|
+
- A **function** as value is called with the current value (`undefined` if the prop doesn't exist) and its result is set. To set a function as the value, use [`set`](#set).
|
|
48
|
+
- Missing parents are created: an array when the next key is an index (`'files.1.name'` on `{}` -> `{ files: [<empty>, { name }] }`), an object otherwise.
|
|
49
|
+
- A primitive or `null` in the middle of a path is replaced by a new object (`'a.b'` on `{ a: 1 }` -> `{ a: { b } }`).
|
|
50
|
+
- Only own props are read: `'toString.value'` creates a `toString` prop instead of reading `Object.prototype.toString`.
|
|
51
|
+
- A path with `'__proto__'` throws (it would change the prototype of the copy).
|
|
52
|
+
- An empty path (`''`) is skipped, and so are symbol keys.
|
|
47
53
|
|
|
48
54
|
```ts
|
|
49
|
-
|
|
50
|
-
'files.1.name': 'new name',
|
|
51
|
-
})
|
|
52
|
-
// The "files" prop is an array. updatedValue = { files: [<empty>, { name: 'new name' }] }
|
|
55
|
+
import { update } from 'maraj'
|
|
53
56
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
'
|
|
57
|
-
|
|
57
|
+
const data = {
|
|
58
|
+
profile: { name: 'Lukasz' },
|
|
59
|
+
works: ['soum', 'fi'],
|
|
60
|
+
history: [
|
|
61
|
+
{ title: 'soum', size: 90, available: true },
|
|
62
|
+
{ title: 'fi', size: 30, available: false },
|
|
63
|
+
],
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const newData = update(data, {
|
|
67
|
+
'profile.name': 'Lucas',
|
|
68
|
+
'works.1': 'gs',
|
|
69
|
+
'history.1.available': (available) => !available,
|
|
70
|
+
'works': (works) => [...works, 'portfolio'], // runs after 'works.1', so it gets ['soum', 'gs']
|
|
58
71
|
})
|
|
59
|
-
// updatedValue2 = { files: { '1': { name: 'new name' } } }
|
|
60
72
|
```
|
|
61
73
|
|
|
62
|
-
|
|
74
|
+
TypeScript only accepts paths that exist in the type of `state`, with values of the same type. Use [`experimental_extendableUpdate`](#experimental_extendableupdate) to add new props.
|
|
75
|
+
|
|
76
|
+
### Options
|
|
77
|
+
|
|
78
|
+
Each option takes `'add'` (default), `'skip'` or `'error'`:
|
|
79
|
+
|
|
80
|
+
- `onNewProps`: a prop doesn't exist, in an object, or a string key in an array.
|
|
81
|
+
- `onNewIndexes`: an index doesn't exist in an array (`'works.5'` on a 2-item array). `'error'` makes sure no empty items are created.
|
|
82
|
+
- `onPathsIntersectedByPrimitiveValues`: a primitive or `null` is in the middle of the path (`'a.b'` on `{ a: 1 }`). `'add'` replaces it with an object.
|
|
83
|
+
|
|
84
|
+
`'skip'` skips only that path, at any depth, and still applies the rest. `'error'` throws an `Error` naming the key and the path.
|
|
63
85
|
|
|
64
86
|
```ts
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
// ts error even if the typing is correct (typescript issue)
|
|
71
|
-
const updateObject1: UpdateObject<T> = {
|
|
72
|
-
[path]: newValue
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// All good, no ts error
|
|
76
|
-
const updateObject2: UpdateObject<T> = {}
|
|
77
|
-
updateObject[path] = newValue
|
|
78
|
-
|
|
79
|
-
}
|
|
87
|
+
update({ a: { d: 1 } }, { 'a.b.c': 1, 'a.d': 2 }, { onNewProps: 'skip' })
|
|
88
|
+
// { a: { d: 2 } }
|
|
89
|
+
|
|
90
|
+
update({ list: [1, 2] }, { 'list.5': 3 }, { onNewIndexes: 'error' })
|
|
91
|
+
// throws: Property/Index "5" doesnt exist in the path "list.5"...
|
|
80
92
|
```
|
|
81
93
|
|
|
82
|
-
|
|
94
|
+
## experimental_extendableUpdate
|
|
95
|
+
|
|
96
|
+
Same as `update`, but TypeScript also accepts new paths and the returned type includes them. It has no options: new props and indexes are always added.
|
|
83
97
|
|
|
84
98
|
```ts
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
'
|
|
89
|
-
'
|
|
99
|
+
import { experimental_extendableUpdate } from 'maraj'
|
|
100
|
+
|
|
101
|
+
const newData = experimental_extendableUpdate(data, {
|
|
102
|
+
'profile.age': 28, // new prop
|
|
103
|
+
'profile.name': 'Lucas',
|
|
104
|
+
'works.10': 'gs', // new index, items 2 to 9 are left empty
|
|
90
105
|
})
|
|
91
106
|
```
|
|
92
107
|
|
|
93
|
-
|
|
108
|
+
A number in the path creates a mutable array when nothing exists there yet. To get an object instead, set it first:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
experimental_extendableUpdate({}, { 'files.1.name': 'new name' })
|
|
112
|
+
// { files: [<empty>, { name: 'new name' }] }
|
|
113
|
+
|
|
114
|
+
experimental_extendableUpdate({}, {
|
|
115
|
+
'files': {},
|
|
116
|
+
'files.1.name': 'new name',
|
|
117
|
+
})
|
|
118
|
+
// { files: { '1': { name: 'new name' } } }
|
|
119
|
+
```
|
|
94
120
|
|
|
95
|
-
|
|
121
|
+
## set
|
|
96
122
|
|
|
97
|
-
|
|
98
|
-
- Update Object
|
|
99
|
-
- Options (to change JS behaviour on non existing props and indexes)
|
|
100
|
-
- 'add': Adds non existing property/index.
|
|
101
|
-
- 'skip': Skips the update in the non-existing prop/index and still applies the rest of the possible updates.
|
|
102
|
-
- '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.
|
|
123
|
+
Returns a function update that always returns the given value. Use it to:
|
|
103
124
|
|
|
104
|
-
|
|
125
|
+
- Set a function as a value (a plain function would be called as an update).
|
|
126
|
+
- Get a stricter type when TypeScript mixes up an optional prop with one that can be `undefined` (usually props of items inside arrays): `set(undefined)` is an error.
|
|
105
127
|
|
|
106
|
-
```
|
|
107
|
-
import { update } from
|
|
128
|
+
```ts
|
|
129
|
+
import { update, set } from 'maraj'
|
|
108
130
|
|
|
109
|
-
const
|
|
110
|
-
profile: { name: "Lukasz" },
|
|
111
|
-
works: ["soum", "fi"],
|
|
112
|
-
history: [
|
|
113
|
-
{ title: "soum", size: 90, available: true, info: ["info1"] },
|
|
114
|
-
{ title: "fi", size: 30, available: false, info: ["infoA"] },
|
|
115
|
-
]
|
|
116
|
-
}
|
|
131
|
+
const button = { label: 'Save', onClick: () => {}, files: [{ name: 'one' }] }
|
|
117
132
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
"history.1.available": (currentValue) => (!currentValue), //functional update
|
|
122
|
-
"works": (v) => [...v, 'portfolio'] //add new value to array
|
|
133
|
+
update(button, {
|
|
134
|
+
'onClick': set(() => console.log('clicked')),
|
|
135
|
+
'files.0.name': set('new name'),
|
|
123
136
|
})
|
|
124
137
|
```
|
|
125
138
|
|
|
126
|
-
##
|
|
127
|
-
|
|
128
|
-
Arguments:
|
|
139
|
+
## remove
|
|
129
140
|
|
|
130
|
-
|
|
131
|
-
- Update Object
|
|
141
|
+
Returns a copy of an object without the given keys, or of an array without the given indexes. Use it inside a function update.
|
|
132
142
|
|
|
133
|
-
|
|
143
|
+
- Objects: only optional keys can be removed (TypeScript).
|
|
144
|
+
- Arrays: indexes as numbers or strings (`1`, `'1'`), in any order; repeated or out-of-range indexes are ignored.
|
|
145
|
+
- Anything other than an object literal or array throws.
|
|
134
146
|
|
|
135
|
-
```
|
|
136
|
-
import {
|
|
147
|
+
```ts
|
|
148
|
+
import { update, remove } from 'maraj'
|
|
137
149
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
works: ["soum", "fi"],
|
|
141
|
-
history: [
|
|
142
|
-
{ title: "soum", size: 90, available: true, info: ["info1"] },
|
|
143
|
-
{ title: "fi", size: 30, available: false, info: ["infoA"] },
|
|
144
|
-
]
|
|
145
|
-
}
|
|
150
|
+
type Person = { profile: { name: string, nickname?: string }, works: string[] }
|
|
151
|
+
const person: Person = { profile: { name: 'Lukasz', nickname: 'Luk' }, works: ['soum', 'fi', 'gs'] }
|
|
146
152
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
"works.10": "gs", //increases the array (filling it up with empty/undefined) and sets the value in the index of 10 to "gs"
|
|
153
|
+
update(person, {
|
|
154
|
+
'profile': (profile) => remove(profile, 'nickname'), // removes "nickname"
|
|
155
|
+
'works': (works) => remove(works, [1, '0']), // ['gs']
|
|
151
156
|
})
|
|
152
157
|
```
|
|
153
158
|
|
|
154
|
-
##
|
|
159
|
+
## select
|
|
155
160
|
|
|
156
|
-
|
|
161
|
+
Returns the value in a dot path, or `undefined` if the path doesn't exist. `''` returns the whole state.
|
|
157
162
|
|
|
158
|
-
|
|
159
|
-
|
|
163
|
+
- Only own props are read: `'profile.toString'` and `'tags.map'` give `undefined`, and so does `'size'` on a `Map`.
|
|
164
|
+
- `null` or `undefined` in the middle of the path gives `undefined`.
|
|
165
|
+
- A key with dots (`{ 'a.b': 1 }`) is found when it matches the whole rest of the path.
|
|
160
166
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
'works': (value) => remove(value, [1, "0"]), // returns new array without the provided index "0" and "1"
|
|
166
|
-
})
|
|
167
|
+
```ts
|
|
168
|
+
import { select } from 'maraj'
|
|
169
|
+
|
|
170
|
+
const work1SizeSelector = (state) => select(state, 'history.1.size') // state.history[1].size
|
|
167
171
|
```
|
|
168
172
|
|
|
169
|
-
##
|
|
173
|
+
## splitPathAtLastKey
|
|
170
174
|
|
|
171
|
-
|
|
175
|
+
Splits a dot path into the path before the last key and the last key (for example, to get an id).
|
|
172
176
|
|
|
173
|
-
```
|
|
174
|
-
import {
|
|
177
|
+
```ts
|
|
178
|
+
import { splitPathAtLastKey } from 'maraj'
|
|
175
179
|
|
|
176
|
-
const
|
|
180
|
+
const [remainingPath, lastKey] = splitPathAtLastKey('projects.1.data.size')
|
|
181
|
+
// remainingPath = 'projects.1.data', lastKey = 'size'
|
|
177
182
|
|
|
178
|
-
|
|
183
|
+
splitPathAtLastKey('size') // ['', 'size']
|
|
179
184
|
```
|
|
180
185
|
|
|
181
|
-
##
|
|
186
|
+
## Type helpers
|
|
182
187
|
|
|
183
|
-
|
|
188
|
+
- `strictType<T, U>(value)`: returns `value` as `U`, and TypeScript errors when `value` has props `U` doesn't have (plain assignment allows them).
|
|
189
|
+
- `strict(value)` (or `s`): returns `value` unchanged, typed as `Strict<T>`.
|
|
190
|
+
- `isObjectLiteral(value)`: `true` when the prototype is `Object.prototype` (`{}`, `{ a: 1 }`); `false` for arrays, `null`, `Object.create(null)`, `Date`, `Map`, class instances and objects from another realm (`node:vm`, iframes).
|
|
191
|
+
- `isStringIndex(key)`: `true` when `key` is an integer written as `parseInt` would write it (`'1'`); `false` for `'01'`, `'1.5'`, `''` and `'NaN'`. `parseStringIndex(key)` returns that number, or `null`.
|
|
192
|
+
- `forEachEntry(object, (key, value) => ...)`: `Object.keys(object).forEach` with typed keys and values.
|
|
184
193
|
|
|
185
|
-
|
|
194
|
+
```ts
|
|
195
|
+
import { strictType } from 'maraj'
|
|
186
196
|
|
|
187
|
-
|
|
188
|
-
|
|
197
|
+
type User = { name: string, age?: number }
|
|
198
|
+
const saveUser = (user: User) => { /* ... */ }
|
|
189
199
|
|
|
190
|
-
|
|
191
|
-
|
|
200
|
+
const user = { name: 'Ana', admin: true }
|
|
201
|
+
saveUser(user) // no error
|
|
202
|
+
saveUser(strictType<typeof user, User>(user)) // error: "admin" isn't in User
|
|
203
|
+
```
|
|
192
204
|
|
|
193
|
-
|
|
205
|
+
## Limitations
|
|
194
206
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
207
|
+
- **Keys with dots** (`{ 'this.is.dotted.key': 123 }`) work only when they already exist and the path ends on them. The path `'a.b.c.d'` works on:
|
|
208
|
+
- `{ 'a.b.c.d': ... }`
|
|
209
|
+
- `{ a: { 'b.c.d': ... } }`
|
|
210
|
+
- `{ a: { b: { 'c.d': ... } } }`
|
|
211
|
+
- `{ a: { b: { c: { d: ... } } } }`
|
|
199
212
|
|
|
200
|
-
|
|
213
|
+
Paths into the value of a dotted key don't: with `{ a: { 'b.c': { d: 1 } } }`, `'a.b.c'` works but `'a.b.c.d'` creates `a.b.c.d` next to `'b.c'`: `{ a: { 'b.c': { d: 1 }, b: { c: { d: ... } } } }`.
|
|
201
214
|
|
|
202
|
-
|
|
215
|
+
- **`UpdateObject` with a computed key** in an object literal is a TypeScript error even when the types are right. Assign the key after creating the object:
|
|
203
216
|
|
|
204
217
|
```ts
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
218
|
+
import type { DotPaths, UpdateObject, UpdateValue } from 'maraj'
|
|
219
|
+
|
|
220
|
+
const updateField = <T, TPath extends DotPaths<T>>(state: T, path: TPath, newValue: UpdateValue<T, TPath>) => {
|
|
221
|
+
// ts error, even if the typing is correct (TypeScript issue)
|
|
222
|
+
const updateObject1: UpdateObject<T> = { [path]: newValue }
|
|
223
|
+
|
|
224
|
+
// no ts error
|
|
225
|
+
const updateObject2: UpdateObject<T> = {}
|
|
226
|
+
updateObject2[path] = newValue
|
|
227
|
+
return update(state, updateObject2)
|
|
228
|
+
}
|
|
211
229
|
```
|
|
230
|
+
|
|
231
|
+
## Benchmarks
|
|
232
|
+
|
|
233
|
+
<!-- bench:start -->
|
|
234
|
+
Median speed against maraj in 11 scenarios (higher is faster)
|
|
235
|
+
|
|
236
|
+
```text
|
|
237
|
+
dot-prop-immutable ██████████████████████████████ 1.26x
|
|
238
|
+
maraj ████████████████████████ 1.00x
|
|
239
|
+
timm ██████████████████ 0.77x
|
|
240
|
+
object-path-immutable ██████████████ 0.58x
|
|
241
|
+
immer (no autofreeze) ████████████ 0.49x
|
|
242
|
+
immutability-helper ██████████ 0.41x
|
|
243
|
+
lodash/fp █████████ 0.38x
|
|
244
|
+
mutative ████████ 0.35x
|
|
245
|
+
immer ███████ 0.30x
|
|
246
|
+
```
|
|
247
|
+
<!-- bench:end -->
|
|
248
|
+
|
|
249
|
+
`1.50x` means 1.5 times as many updates per second as maraj. The scenarios go from one top-level prop to 100 paths in a 1,000-item array: see [benchmarks/README.md](benchmarks/README.md) for each one, the machine and how to run them.
|
package/dist/index.d.mts
CHANGED
|
@@ -6,13 +6,11 @@
|
|
|
6
6
|
/** Dot-paths of an array. */
|
|
7
7
|
type ArrayPaths<TInnerType, TAllowedTypes> = TInnerType extends TAllowedTypes ? TInnerType extends PrimitivesAndNativeObjects ? ExtendedArrayIndexes : ExtendedArrayIndexes | `${ExtendedArrayIndexes}.${DotPathsImplementation<TInnerType, TAllowedTypes>}` : `${ExtendedArrayIndexes}.${DotPathsImplementation<TInnerType, TAllowedTypes>}`;
|
|
8
8
|
/** Dot-paths of an object. */
|
|
9
|
-
type ObjectPaths<T, TAllowedTypes> = {
|
|
10
|
-
[Key in keyof T & (string | number)]: T[Key] extends TAllowedTypes ? T[Key] extends PrimitivesAndNativeObjects ? `${Key}` : `${Key}` | `${Key}.${DotPathsImplementation<T[Key], TAllowedTypes>}` : `${Key}.${DotPathsImplementation<T[Key], TAllowedTypes>}`;
|
|
11
|
-
}[keyof T & (string | number)] & {};
|
|
9
|
+
type ObjectPaths<T, TAllowedTypes> = { [Key in keyof T & (string | number)]: T[Key] extends TAllowedTypes ? T[Key] extends PrimitivesAndNativeObjects ? `${Key}` : `${Key}` | `${Key}.${DotPathsImplementation<T[Key], TAllowedTypes>}` : `${Key}.${DotPathsImplementation<T[Key], TAllowedTypes>}`; }[keyof T & (string | number)];
|
|
12
10
|
/** Dot-paths of a tuple. */
|
|
13
|
-
type TuplePaths<T, TAllowedTypes> = ObjectPaths<Omit<T, keyof any[]
|
|
14
|
-
/** Dot-paths implementation */
|
|
15
|
-
type DotPathsImplementation<T, TAllowedTypes = any> = T extends ReadonlyArray<infer U> ? T extends Tuple ? TuplePaths<T, TAllowedTypes> : ArrayPaths<U, TAllowedTypes> : T extends PrimitivesAndNativeObjects ? never : ObjectPaths<T
|
|
11
|
+
type TuplePaths<T, TAllowedTypes> = ObjectPaths<Required<Omit<T, keyof any[]>>, TAllowedTypes>;
|
|
12
|
+
/** Dot-paths implementation, Required<T> so optional props count as their type ('nickname?: string' is a string) */
|
|
13
|
+
type DotPathsImplementation<T, TAllowedTypes = any> = T extends ReadonlyArray<infer U> ? T extends Tuple ? TuplePaths<T, TAllowedTypes> : ArrayPaths<U, TAllowedTypes> : T extends PrimitivesAndNativeObjects ? never : ObjectPaths<Required<T>, TAllowedTypes>;
|
|
16
14
|
/** Literal union of all posible dot-paths which satisfy provided types as second argument (default: any). */
|
|
17
15
|
type DotPaths<T, TAllowedTypes = any> = KeyOf<T, TAllowedTypes> | DotPathsImplementation<T, TAllowedTypes>;
|
|
18
16
|
/**
|
|
@@ -20,15 +18,17 @@ type DotPaths<T, TAllowedTypes = any> = KeyOf<T, TAllowedTypes> | DotPathsImplem
|
|
|
20
18
|
* VALUE OF A NESTED PROPERTY PROVIDING A DOT PATH
|
|
21
19
|
* --------------------------------------------
|
|
22
20
|
*/
|
|
23
|
-
/**
|
|
24
|
-
type
|
|
21
|
+
/** Tuple without rest items ([number, string], not [string, ...number[]]): an index that isn't a key is out of range. */
|
|
22
|
+
type IsFixedTuple<T> = T extends Tuple ? number extends T['length'] ? false : true : false;
|
|
23
|
+
/** Nested type implementation, goes into each object of a union ({ name } | null -> 'name' is string). */
|
|
24
|
+
type ValueInPath<TObject, TPath> = TObject extends unknown ? TPath extends keyof TObject ? TObject[TPath] : TPath extends '' ? TObject : TPath extends LiteralIndex ? never : TPath extends `${number}` ? IsFixedTuple<TObject> extends true ? never : 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}` ? IsFixedTuple<TObject> extends true ? never : TObject extends ReadonlyArray<infer U> ? ValueInPath<U, R> : never : never : never : never;
|
|
25
25
|
/**
|
|
26
26
|
* --------------------------------------------
|
|
27
27
|
* RETURNED VALUE OF A NESTED PROPERTY PROVIDING A DOT PATH
|
|
28
28
|
* --------------------------------------------
|
|
29
29
|
*/
|
|
30
|
-
/** Returned nested type implementation. */
|
|
31
|
-
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;
|
|
30
|
+
/** Returned nested type implementation, null or undefined inside the path -> undefined. */
|
|
31
|
+
type ReturnedValueInPath<TObject, TPath> = TPath extends '' ? TObject : TObject extends null | undefined ? undefined : TPath extends keyof TObject ? TPath extends number ? TObject extends ReadonlyArray<infer U> ? (U | undefined) : TObject[TPath] : TObject[TPath] : TPath extends `${number}` ? IsFixedTuple<TObject> extends true ? never : 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}` ? IsFixedTuple<TObject> extends true ? never : TObject extends ReadonlyArray<infer U> ? (ReturnedValueInPath<U, R> | undefined) : never : never : never;
|
|
32
32
|
/**
|
|
33
33
|
* --------------------------------------------
|
|
34
34
|
* UPDATE OBJECT WITH DOT PATH IMPLEMENTATION
|
|
@@ -37,9 +37,7 @@ type ReturnedValueInPath<TObject, TPath> = TPath extends '' ? TObject : TPath ex
|
|
|
37
37
|
/** Value of a dot-path update object, can be the value or a function. */
|
|
38
38
|
type UpdateValue<TObject, TPath> = ValueInPath<TObject, TPath> extends never ? never : ValueInPath<TObject, TPath> | ((fieldValue: ValueInPath<TObject, TPath>) => Strict<ValueInPath<TObject, TPath>>);
|
|
39
39
|
/** Dot-path update object, used to give updates to the updateImmutably function. */
|
|
40
|
-
type UpdateObject<TObject, TPaths extends DotPaths<TObject> = DotPaths<TObject>> = {
|
|
41
|
-
[Path in TPaths]?: UpdateValue<TObject, Path>;
|
|
42
|
-
};
|
|
40
|
+
type UpdateObject<TObject, TPaths extends DotPaths<TObject> = DotPaths<TObject>> = { [Path in TPaths]?: UpdateValue<TObject, Path>; };
|
|
43
41
|
/**
|
|
44
42
|
* --------------------------------------------
|
|
45
43
|
* EXTRACT TYPE FROM DOT-PATH UPDATE OBJECT
|
|
@@ -47,78 +45,54 @@ type UpdateObject<TObject, TPaths extends DotPaths<TObject> = DotPaths<TObject>>
|
|
|
47
45
|
*/
|
|
48
46
|
/** Merging two objects */
|
|
49
47
|
/** Keys which arent dot-path keys */
|
|
50
|
-
type NonDotPathKeys<T> = {
|
|
51
|
-
[Key in keyof T]: Key extends `${infer K}.${string}` ? K : Key;
|
|
52
|
-
}[keyof T];
|
|
48
|
+
type NonDotPathKeys<T> = { [Key in keyof T]: Key extends `${infer K}.${string}` ? K : Key; }[keyof T];
|
|
53
49
|
/** Keys which are an index */
|
|
54
|
-
type KeysRepresentingAnIndex<T> = {
|
|
55
|
-
[Key in keyof T]: Key extends `${number}.${string}` ? never : Key;
|
|
56
|
-
}[keyof T];
|
|
50
|
+
type KeysRepresentingAnIndex<T> = { [Key in keyof T]: Key extends `${number}.${string}` ? never : Key; }[keyof T];
|
|
57
51
|
/** Keys which start with an index */
|
|
58
|
-
type KeyPathsStartingWithAnIndex<T> = {
|
|
59
|
-
[Key in keyof T]: Key extends `${number}.${string}` ? Key : never;
|
|
60
|
-
}[keyof T];
|
|
52
|
+
type KeyPathsStartingWithAnIndex<T> = { [Key in keyof T]: Key extends `${number}.${string}` ? Key : never; }[keyof T];
|
|
61
53
|
/** Keys which are paths and its first key-path is removed */
|
|
62
|
-
type NestedPathKeys<T, K extends string | number> = {
|
|
63
|
-
[Key in keyof T]: Key extends `${K}.${infer U}` ? U : never;
|
|
64
|
-
}[keyof T];
|
|
54
|
+
type NestedPathKeys<T, K extends string | number> = { [Key in keyof T]: Key extends `${K}.${infer U}` ? U : never; }[keyof T];
|
|
65
55
|
/** Extract value if its a function */
|
|
66
|
-
type Value<T> = T extends (...args: any) => any ? ReturnType<T> : T;
|
|
56
|
+
type Value<T> = T extends ((...args: any) => any) ? ReturnType<T> : T;
|
|
67
57
|
/** To check if an empty object is provided */
|
|
68
58
|
type EmptyObject = Record<PropertyKey, never>;
|
|
69
59
|
/** Used to extract the type from a dot-path update object. */
|
|
70
|
-
type ExtractTypeFromDotPathUpdateObject<T extends Record<string, any>> = T extends EmptyObject ? {} : keyof T extends LiteralIndex | number | `${number}` | `${number}.${infer U}` ? Value<T[KeyPathsStartingWithAnIndex<T>]> extends never ? Array<Value<T[KeysRepresentingAnIndex<T>]>> : Array<Value<T[KeysRepresentingAnIndex<T>]> | {
|
|
71
|
-
[Key2 in U]: Value<T[KeyPathsStartingWithAnIndex<T>]>;
|
|
72
|
-
}> : {
|
|
73
|
-
[Key1 in NonDotPathKeys<T> & string]: Key1 extends keyof T ? Value<T[Key1]> extends Array<infer U> ? ExtractTypeFromDotPathUpdateObject<{
|
|
74
|
-
[Key2 in NestedPathKeys<T, Key1>]: Value<T[`${Key1}.${Key2}`]>;
|
|
75
|
-
}> extends Array<infer W> ? Array<U | W> : Array<U> & ExtractTypeFromDotPathUpdateObject<{
|
|
76
|
-
[Key2 in NestedPathKeys<T, Key1>]: Value<T[`${Key1}.${Key2}`]>;
|
|
77
|
-
}> : Value<T[Key1]> : ExtractTypeFromDotPathUpdateObject<{
|
|
78
|
-
[Key2 in NestedPathKeys<T, Key1>]: Value<T[`${Key1}.${Key2}`]>;
|
|
79
|
-
}>;
|
|
80
|
-
} & unknown;
|
|
60
|
+
type ExtractTypeFromDotPathUpdateObject<T extends Record<string, any>> = T extends EmptyObject ? {} : keyof T extends LiteralIndex | number | `${number}` | `${number}.${infer U}` ? Value<T[KeyPathsStartingWithAnIndex<T>]> extends never ? Array<Value<T[KeysRepresentingAnIndex<T>]>> : Array<Value<T[KeysRepresentingAnIndex<T>]> | { [Key2 in U]: Value<T[KeyPathsStartingWithAnIndex<T>]>; }> : { [Key1 in NonDotPathKeys<T> & string]: Key1 extends keyof T ? Value<T[Key1]> extends Array<infer U> ? ExtractTypeFromDotPathUpdateObject<{ [Key2 in NestedPathKeys<T, Key1>]: Value<T[`${Key1}.${Key2}`]>; }> extends Array<infer W> ? Array<U | W> : Array<U> & ExtractTypeFromDotPathUpdateObject<{ [Key2 in NestedPathKeys<T, Key1>]: Value<T[`${Key1}.${Key2}`]>; }> : Value<T[Key1]> : ExtractTypeFromDotPathUpdateObject<{ [Key2 in NestedPathKeys<T, Key1>]: Value<T[`${Key1}.${Key2}`]>; }>; } & unknown;
|
|
81
61
|
/** New expanded value after aplying updates including new properties */
|
|
82
62
|
type ExtendedUpdate<TObject, TDotPathUpdateObject extends Record<PropertyKey, any>> = TObject extends Array<infer U> ? ExtractTypeFromDotPathUpdateObject<TDotPathUpdateObject> extends Array<infer W> ? Array<U | W> : TObject & ExtractTypeFromDotPathUpdateObject<TDotPathUpdateObject> : TObject & ExtractTypeFromDotPathUpdateObject<TDotPathUpdateObject>;
|
|
83
|
-
|
|
84
63
|
/** Index literal type to improve DX at managing updates. */
|
|
85
64
|
declare const LITERAL_INDEX = "${number}";
|
|
86
|
-
|
|
87
65
|
/** Primitives and browser native objects. */
|
|
88
|
-
type PrimitivesAndNativeObjects = null | undefined | string | number | boolean | symbol | bigint | Date | FileList | File;
|
|
66
|
+
type PrimitivesAndNativeObjects = null | undefined | string | number | boolean | symbol | bigint | Date | FileList | File | Blob;
|
|
89
67
|
/** Tuple type, it has to have at least property "0" */
|
|
90
68
|
type Tuple = ReadonlyArray<any> & {
|
|
91
|
-
|
|
69
|
+
"0": any;
|
|
92
70
|
};
|
|
93
71
|
/** Array indexes type. */
|
|
94
72
|
type LiteralIndex = typeof LITERAL_INDEX;
|
|
95
73
|
type ExtendedArrayIndexes = number | `${number}` | LiteralIndex;
|
|
96
|
-
/** Object Literal */
|
|
74
|
+
/** Object Literal, File and Blob still match it (they have no symbol to reject them by) */
|
|
97
75
|
type ObjectLiteral = {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
76
|
+
[x: string]: any;
|
|
77
|
+
[x: number]: any;
|
|
78
|
+
[x: symbol]: any;
|
|
79
|
+
[Symbol.iterator]?: never;
|
|
80
|
+
[Symbol.toPrimitive]?: never;
|
|
81
|
+
[Symbol.hasInstance]?: never;
|
|
82
|
+
[Symbol.unscopables]?: never;
|
|
83
|
+
[Symbol.matchAll]?: never;
|
|
84
|
+
[Symbol.toStringTag]?: never;
|
|
106
85
|
};
|
|
107
86
|
/** Strict key */
|
|
108
87
|
declare const strictSymbol: unique symbol;
|
|
109
|
-
type Strict<T> = T extends ObjectLiteral ? T & {
|
|
110
|
-
|
|
88
|
+
type Strict<T> = T extends PrimitivesAndNativeObjects ? T : T extends ObjectLiteral ? T & {
|
|
89
|
+
[strictSymbol]: DotPaths<T>;
|
|
111
90
|
} : T;
|
|
112
91
|
/** Smart KeyOf (doesnt include the "strict" key) */
|
|
113
|
-
type KeyOf<T, TAllowedValuesInKeys = any> = T extends ObjectLiteral ? T extends Strict<infer U> ? KeysOfObject<U, TAllowedValuesInKeys> : KeysOfObject<T, TAllowedValuesInKeys> : T extends Tuple ? KeysOfObject<Omit<T, keyof any[]>, TAllowedValuesInKeys> : T extends ReadonlyArray<infer U> ? U extends TAllowedValuesInKeys ? ExtendedArrayIndexes : never : never;
|
|
114
|
-
type KeysOfObject<T, TAllowedValuesInKeys> = {
|
|
115
|
-
[Key in keyof T]: T[Key] extends TAllowedValuesInKeys ? Key : never;
|
|
116
|
-
}[keyof T];
|
|
117
|
-
|
|
92
|
+
type KeyOf<T, TAllowedValuesInKeys = any> = T extends PrimitivesAndNativeObjects ? never : T extends ObjectLiteral ? T extends Strict<infer U> ? KeysOfObject<U, TAllowedValuesInKeys> : KeysOfObject<T, TAllowedValuesInKeys> : T extends Tuple ? KeysOfObject<Omit<T, keyof any[]>, TAllowedValuesInKeys> : T extends ReadonlyArray<infer U> ? U extends TAllowedValuesInKeys ? ExtendedArrayIndexes : never : never;
|
|
93
|
+
type KeysOfObject<T, TAllowedValuesInKeys> = { [Key in keyof T]-?: Required<T>[Key] extends TAllowedValuesInKeys ? Key : never; }[keyof T];
|
|
118
94
|
/** Returns only the optional keys of an object. */
|
|
119
|
-
type OptionalKeys<T> = {
|
|
120
|
-
[K in keyof T]-?: {} extends Pick<T, K> ? K : never;
|
|
121
|
-
}[keyof T];
|
|
95
|
+
type OptionalKeys<T> = { [K in keyof T]-?: {} extends Pick<T, K> ? K : never; }[keyof T];
|
|
122
96
|
/** Removes properties or indexes, order doesn't matter. */
|
|
123
97
|
type Remove = <T extends ObjectLiteral | any[]>(value: T, keys: T extends any[] ? (number | `${number}` | (number | `${number}`)[]) : OptionalKeys<T> | (OptionalKeys<T>)[]) => T;
|
|
124
98
|
/**
|
|
@@ -127,11 +101,10 @@ type Remove = <T extends ObjectLiteral | any[]>(value: T, keys: T extends any[]
|
|
|
127
101
|
* @param keys Keys to remove.
|
|
128
102
|
* @returns New object/array without the provided keys/indexes.
|
|
129
103
|
*/
|
|
130
|
-
declare const remove: Remove;
|
|
131
|
-
|
|
104
|
+
export declare const remove: Remove;
|
|
132
105
|
type Select = {
|
|
133
|
-
|
|
134
|
-
|
|
106
|
+
<T, TPath extends DotPaths<T>>(state: T, path: TPath): ReturnedValueInPath<T, TPath>;
|
|
107
|
+
<T, TPath extends ''>(state: T, path: TPath): T;
|
|
135
108
|
};
|
|
136
109
|
/**
|
|
137
110
|
* Returns the value from a given dot path of an object/array or undefined if doesn't exist.
|
|
@@ -139,8 +112,7 @@ type Select = {
|
|
|
139
112
|
* @param path Path indicating the value to extract.
|
|
140
113
|
* @returns Value of the provided path or undefined.
|
|
141
114
|
*/
|
|
142
|
-
declare const select: Select;
|
|
143
|
-
|
|
115
|
+
export declare const select: Select;
|
|
144
116
|
type PathWithoutLastKey = string;
|
|
145
117
|
type LastKey = string;
|
|
146
118
|
type SplitDotPathAtLastKey = <T extends string>(dotPath: T) => [PathWithoutLastKey, LastKey];
|
|
@@ -149,21 +121,19 @@ type SplitDotPathAtLastKey = <T extends string>(dotPath: T) => [PathWithoutLastK
|
|
|
149
121
|
* @param dotPath A dot path.
|
|
150
122
|
* @returns [pathWithoutLastKey, lastKey] or ['', lastKey].
|
|
151
123
|
*/
|
|
152
|
-
declare const splitPathAtLastKey: SplitDotPathAtLastKey;
|
|
153
|
-
|
|
124
|
+
export declare const splitPathAtLastKey: SplitDotPathAtLastKey;
|
|
154
125
|
type Set = <T>(newValue: T) => (v: unknown) => T;
|
|
155
126
|
/**
|
|
156
127
|
* Allows to set strongly typed values (removing inacurate "undefined" inference) in nested values inside arrays.
|
|
157
128
|
* @param newValue New value.
|
|
158
129
|
* @returns The same value.
|
|
159
130
|
*/
|
|
160
|
-
declare const set: Set;
|
|
161
|
-
|
|
131
|
+
export declare const set: Set;
|
|
162
132
|
type OptionValues = 'error' | 'skip' | 'add';
|
|
163
133
|
type Options = {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
134
|
+
onNewProps?: OptionValues;
|
|
135
|
+
onNewIndexes?: OptionValues;
|
|
136
|
+
onPathsIntersectedByPrimitiveValues?: OptionValues;
|
|
167
137
|
};
|
|
168
138
|
type ImmutableUpdate = <TObject, TAllowedDotPathKeys extends DotPaths<TObject> = DotPaths<TObject>>(state: TObject, dotPathUpdateObject: UpdateObject<TObject, TAllowedDotPathKeys>, options?: Options) => TObject;
|
|
169
139
|
/**
|
|
@@ -175,7 +145,7 @@ type ImmutableUpdate = <TObject, TAllowedDotPathKeys extends DotPaths<TObject> =
|
|
|
175
145
|
* @param options Options to change JS behaviour on non-existent fields.
|
|
176
146
|
* @returns New Updated Object.
|
|
177
147
|
*/
|
|
178
|
-
declare const update: ImmutableUpdate;
|
|
148
|
+
export declare const update: ImmutableUpdate;
|
|
179
149
|
type ExtendableImmutableUpdate = <TObject, TUpdateObject extends UpdateObject<TObject> = UpdateObject<TObject>>(state: TObject, dotPathUpdateObject: TUpdateObject) => ExtendedUpdate<TObject, TUpdateObject>;
|
|
180
150
|
/**
|
|
181
151
|
* Creates a new object applying immutable updates using dot-path syntax.
|
|
@@ -185,26 +155,21 @@ type ExtendableImmutableUpdate = <TObject, TUpdateObject extends UpdateObject<TO
|
|
|
185
155
|
* @param dotPathUpdateObject Dot Path Update Object.
|
|
186
156
|
* @returns New Updated Object.
|
|
187
157
|
*/
|
|
188
|
-
declare const experimental_extendableUpdate: ExtendableImmutableUpdate;
|
|
189
|
-
|
|
158
|
+
export declare const experimental_extendableUpdate: ExtendableImmutableUpdate;
|
|
190
159
|
type ForEachEntry = <T extends ObjectLiteral>(object: T, callbackfn: (key: keyof T, value: T[keyof T]) => void) => void;
|
|
191
|
-
declare const forEachEntry: ForEachEntry;
|
|
192
|
-
|
|
160
|
+
export declare const forEachEntry: ForEachEntry;
|
|
193
161
|
/** Checks if any provided value is an object literal or not */
|
|
194
162
|
type IsObjectLiteral = (valueToTest: unknown) => valueToTest is ObjectLiteral;
|
|
195
|
-
declare const isObjectLiteral: IsObjectLiteral;
|
|
196
|
-
|
|
163
|
+
export declare const isObjectLiteral: IsObjectLiteral;
|
|
197
164
|
/** Adds strict property to an object literal */
|
|
198
165
|
type StrictFn = <T>(value: T) => Strict<T>;
|
|
199
|
-
declare const strict: StrictFn;
|
|
200
|
-
declare const s: StrictFn;
|
|
166
|
+
export declare const strict: StrictFn;
|
|
167
|
+
export declare const s: StrictFn;
|
|
201
168
|
/** Checks the strictness of a type passed to a function or callback without 3rd party implementation */
|
|
202
|
-
type
|
|
203
|
-
declare const
|
|
204
|
-
|
|
169
|
+
type StrictType = <T extends U, U>(v: T extends U ? DotPaths<T> extends DotPaths<U> ? T : Exclude<DotPaths<T>, DotPaths<U>> : never) => U;
|
|
170
|
+
export declare const strictType: StrictType;
|
|
205
171
|
type ParseStringIndex = (stringKey: string) => number | null;
|
|
206
|
-
declare const parseStringIndex: ParseStringIndex;
|
|
172
|
+
export declare const parseStringIndex: ParseStringIndex;
|
|
207
173
|
type IsStringIndex = (stringKey: string) => stringKey is `${number}`;
|
|
208
|
-
declare const isStringIndex: IsStringIndex;
|
|
209
|
-
|
|
210
|
-
export { type DotPaths, type ExtendedArrayIndexes, type KeyOf, type LiteralIndex, type ObjectLiteral, type PrimitivesAndNativeObjects, type ReturnedValueInPath, type Strict, type Tuple, type UpdateObject, type UpdateValue, type ValueInPath, experimental_extendableUpdate, forEachEntry, isObjectLiteral, isStringIndex, parseStringIndex, remove, s, select, set, splitPathAtLastKey, strict, strictValueWrapper, update };
|
|
174
|
+
export declare const isStringIndex: IsStringIndex;
|
|
175
|
+
export type { DotPaths, ExtendedArrayIndexes, KeyOf, LiteralIndex, ObjectLiteral, PrimitivesAndNativeObjects, ReturnedValueInPath, Strict, Tuple, UpdateObject, UpdateValue, ValueInPath };
|
package/dist/index.d.ts
CHANGED
|
@@ -6,13 +6,11 @@
|
|
|
6
6
|
/** Dot-paths of an array. */
|
|
7
7
|
type ArrayPaths<TInnerType, TAllowedTypes> = TInnerType extends TAllowedTypes ? TInnerType extends PrimitivesAndNativeObjects ? ExtendedArrayIndexes : ExtendedArrayIndexes | `${ExtendedArrayIndexes}.${DotPathsImplementation<TInnerType, TAllowedTypes>}` : `${ExtendedArrayIndexes}.${DotPathsImplementation<TInnerType, TAllowedTypes>}`;
|
|
8
8
|
/** Dot-paths of an object. */
|
|
9
|
-
type ObjectPaths<T, TAllowedTypes> = {
|
|
10
|
-
[Key in keyof T & (string | number)]: T[Key] extends TAllowedTypes ? T[Key] extends PrimitivesAndNativeObjects ? `${Key}` : `${Key}` | `${Key}.${DotPathsImplementation<T[Key], TAllowedTypes>}` : `${Key}.${DotPathsImplementation<T[Key], TAllowedTypes>}`;
|
|
11
|
-
}[keyof T & (string | number)] & {};
|
|
9
|
+
type ObjectPaths<T, TAllowedTypes> = { [Key in keyof T & (string | number)]: T[Key] extends TAllowedTypes ? T[Key] extends PrimitivesAndNativeObjects ? `${Key}` : `${Key}` | `${Key}.${DotPathsImplementation<T[Key], TAllowedTypes>}` : `${Key}.${DotPathsImplementation<T[Key], TAllowedTypes>}`; }[keyof T & (string | number)];
|
|
12
10
|
/** Dot-paths of a tuple. */
|
|
13
|
-
type TuplePaths<T, TAllowedTypes> = ObjectPaths<Omit<T, keyof any[]
|
|
14
|
-
/** Dot-paths implementation */
|
|
15
|
-
type DotPathsImplementation<T, TAllowedTypes = any> = T extends ReadonlyArray<infer U> ? T extends Tuple ? TuplePaths<T, TAllowedTypes> : ArrayPaths<U, TAllowedTypes> : T extends PrimitivesAndNativeObjects ? never : ObjectPaths<T
|
|
11
|
+
type TuplePaths<T, TAllowedTypes> = ObjectPaths<Required<Omit<T, keyof any[]>>, TAllowedTypes>;
|
|
12
|
+
/** Dot-paths implementation, Required<T> so optional props count as their type ('nickname?: string' is a string) */
|
|
13
|
+
type DotPathsImplementation<T, TAllowedTypes = any> = T extends ReadonlyArray<infer U> ? T extends Tuple ? TuplePaths<T, TAllowedTypes> : ArrayPaths<U, TAllowedTypes> : T extends PrimitivesAndNativeObjects ? never : ObjectPaths<Required<T>, TAllowedTypes>;
|
|
16
14
|
/** Literal union of all posible dot-paths which satisfy provided types as second argument (default: any). */
|
|
17
15
|
type DotPaths<T, TAllowedTypes = any> = KeyOf<T, TAllowedTypes> | DotPathsImplementation<T, TAllowedTypes>;
|
|
18
16
|
/**
|
|
@@ -20,15 +18,17 @@ type DotPaths<T, TAllowedTypes = any> = KeyOf<T, TAllowedTypes> | DotPathsImplem
|
|
|
20
18
|
* VALUE OF A NESTED PROPERTY PROVIDING A DOT PATH
|
|
21
19
|
* --------------------------------------------
|
|
22
20
|
*/
|
|
23
|
-
/**
|
|
24
|
-
type
|
|
21
|
+
/** Tuple without rest items ([number, string], not [string, ...number[]]): an index that isn't a key is out of range. */
|
|
22
|
+
type IsFixedTuple<T> = T extends Tuple ? number extends T['length'] ? false : true : false;
|
|
23
|
+
/** Nested type implementation, goes into each object of a union ({ name } | null -> 'name' is string). */
|
|
24
|
+
type ValueInPath<TObject, TPath> = TObject extends unknown ? TPath extends keyof TObject ? TObject[TPath] : TPath extends '' ? TObject : TPath extends LiteralIndex ? never : TPath extends `${number}` ? IsFixedTuple<TObject> extends true ? never : 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}` ? IsFixedTuple<TObject> extends true ? never : TObject extends ReadonlyArray<infer U> ? ValueInPath<U, R> : never : never : never : never;
|
|
25
25
|
/**
|
|
26
26
|
* --------------------------------------------
|
|
27
27
|
* RETURNED VALUE OF A NESTED PROPERTY PROVIDING A DOT PATH
|
|
28
28
|
* --------------------------------------------
|
|
29
29
|
*/
|
|
30
|
-
/** Returned nested type implementation. */
|
|
31
|
-
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;
|
|
30
|
+
/** Returned nested type implementation, null or undefined inside the path -> undefined. */
|
|
31
|
+
type ReturnedValueInPath<TObject, TPath> = TPath extends '' ? TObject : TObject extends null | undefined ? undefined : TPath extends keyof TObject ? TPath extends number ? TObject extends ReadonlyArray<infer U> ? (U | undefined) : TObject[TPath] : TObject[TPath] : TPath extends `${number}` ? IsFixedTuple<TObject> extends true ? never : 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}` ? IsFixedTuple<TObject> extends true ? never : TObject extends ReadonlyArray<infer U> ? (ReturnedValueInPath<U, R> | undefined) : never : never : never;
|
|
32
32
|
/**
|
|
33
33
|
* --------------------------------------------
|
|
34
34
|
* UPDATE OBJECT WITH DOT PATH IMPLEMENTATION
|
|
@@ -37,9 +37,7 @@ type ReturnedValueInPath<TObject, TPath> = TPath extends '' ? TObject : TPath ex
|
|
|
37
37
|
/** Value of a dot-path update object, can be the value or a function. */
|
|
38
38
|
type UpdateValue<TObject, TPath> = ValueInPath<TObject, TPath> extends never ? never : ValueInPath<TObject, TPath> | ((fieldValue: ValueInPath<TObject, TPath>) => Strict<ValueInPath<TObject, TPath>>);
|
|
39
39
|
/** Dot-path update object, used to give updates to the updateImmutably function. */
|
|
40
|
-
type UpdateObject<TObject, TPaths extends DotPaths<TObject> = DotPaths<TObject>> = {
|
|
41
|
-
[Path in TPaths]?: UpdateValue<TObject, Path>;
|
|
42
|
-
};
|
|
40
|
+
type UpdateObject<TObject, TPaths extends DotPaths<TObject> = DotPaths<TObject>> = { [Path in TPaths]?: UpdateValue<TObject, Path>; };
|
|
43
41
|
/**
|
|
44
42
|
* --------------------------------------------
|
|
45
43
|
* EXTRACT TYPE FROM DOT-PATH UPDATE OBJECT
|
|
@@ -47,78 +45,54 @@ type UpdateObject<TObject, TPaths extends DotPaths<TObject> = DotPaths<TObject>>
|
|
|
47
45
|
*/
|
|
48
46
|
/** Merging two objects */
|
|
49
47
|
/** Keys which arent dot-path keys */
|
|
50
|
-
type NonDotPathKeys<T> = {
|
|
51
|
-
[Key in keyof T]: Key extends `${infer K}.${string}` ? K : Key;
|
|
52
|
-
}[keyof T];
|
|
48
|
+
type NonDotPathKeys<T> = { [Key in keyof T]: Key extends `${infer K}.${string}` ? K : Key; }[keyof T];
|
|
53
49
|
/** Keys which are an index */
|
|
54
|
-
type KeysRepresentingAnIndex<T> = {
|
|
55
|
-
[Key in keyof T]: Key extends `${number}.${string}` ? never : Key;
|
|
56
|
-
}[keyof T];
|
|
50
|
+
type KeysRepresentingAnIndex<T> = { [Key in keyof T]: Key extends `${number}.${string}` ? never : Key; }[keyof T];
|
|
57
51
|
/** Keys which start with an index */
|
|
58
|
-
type KeyPathsStartingWithAnIndex<T> = {
|
|
59
|
-
[Key in keyof T]: Key extends `${number}.${string}` ? Key : never;
|
|
60
|
-
}[keyof T];
|
|
52
|
+
type KeyPathsStartingWithAnIndex<T> = { [Key in keyof T]: Key extends `${number}.${string}` ? Key : never; }[keyof T];
|
|
61
53
|
/** Keys which are paths and its first key-path is removed */
|
|
62
|
-
type NestedPathKeys<T, K extends string | number> = {
|
|
63
|
-
[Key in keyof T]: Key extends `${K}.${infer U}` ? U : never;
|
|
64
|
-
}[keyof T];
|
|
54
|
+
type NestedPathKeys<T, K extends string | number> = { [Key in keyof T]: Key extends `${K}.${infer U}` ? U : never; }[keyof T];
|
|
65
55
|
/** Extract value if its a function */
|
|
66
|
-
type Value<T> = T extends (...args: any) => any ? ReturnType<T> : T;
|
|
56
|
+
type Value<T> = T extends ((...args: any) => any) ? ReturnType<T> : T;
|
|
67
57
|
/** To check if an empty object is provided */
|
|
68
58
|
type EmptyObject = Record<PropertyKey, never>;
|
|
69
59
|
/** Used to extract the type from a dot-path update object. */
|
|
70
|
-
type ExtractTypeFromDotPathUpdateObject<T extends Record<string, any>> = T extends EmptyObject ? {} : keyof T extends LiteralIndex | number | `${number}` | `${number}.${infer U}` ? Value<T[KeyPathsStartingWithAnIndex<T>]> extends never ? Array<Value<T[KeysRepresentingAnIndex<T>]>> : Array<Value<T[KeysRepresentingAnIndex<T>]> | {
|
|
71
|
-
[Key2 in U]: Value<T[KeyPathsStartingWithAnIndex<T>]>;
|
|
72
|
-
}> : {
|
|
73
|
-
[Key1 in NonDotPathKeys<T> & string]: Key1 extends keyof T ? Value<T[Key1]> extends Array<infer U> ? ExtractTypeFromDotPathUpdateObject<{
|
|
74
|
-
[Key2 in NestedPathKeys<T, Key1>]: Value<T[`${Key1}.${Key2}`]>;
|
|
75
|
-
}> extends Array<infer W> ? Array<U | W> : Array<U> & ExtractTypeFromDotPathUpdateObject<{
|
|
76
|
-
[Key2 in NestedPathKeys<T, Key1>]: Value<T[`${Key1}.${Key2}`]>;
|
|
77
|
-
}> : Value<T[Key1]> : ExtractTypeFromDotPathUpdateObject<{
|
|
78
|
-
[Key2 in NestedPathKeys<T, Key1>]: Value<T[`${Key1}.${Key2}`]>;
|
|
79
|
-
}>;
|
|
80
|
-
} & unknown;
|
|
60
|
+
type ExtractTypeFromDotPathUpdateObject<T extends Record<string, any>> = T extends EmptyObject ? {} : keyof T extends LiteralIndex | number | `${number}` | `${number}.${infer U}` ? Value<T[KeyPathsStartingWithAnIndex<T>]> extends never ? Array<Value<T[KeysRepresentingAnIndex<T>]>> : Array<Value<T[KeysRepresentingAnIndex<T>]> | { [Key2 in U]: Value<T[KeyPathsStartingWithAnIndex<T>]>; }> : { [Key1 in NonDotPathKeys<T> & string]: Key1 extends keyof T ? Value<T[Key1]> extends Array<infer U> ? ExtractTypeFromDotPathUpdateObject<{ [Key2 in NestedPathKeys<T, Key1>]: Value<T[`${Key1}.${Key2}`]>; }> extends Array<infer W> ? Array<U | W> : Array<U> & ExtractTypeFromDotPathUpdateObject<{ [Key2 in NestedPathKeys<T, Key1>]: Value<T[`${Key1}.${Key2}`]>; }> : Value<T[Key1]> : ExtractTypeFromDotPathUpdateObject<{ [Key2 in NestedPathKeys<T, Key1>]: Value<T[`${Key1}.${Key2}`]>; }>; } & unknown;
|
|
81
61
|
/** New expanded value after aplying updates including new properties */
|
|
82
62
|
type ExtendedUpdate<TObject, TDotPathUpdateObject extends Record<PropertyKey, any>> = TObject extends Array<infer U> ? ExtractTypeFromDotPathUpdateObject<TDotPathUpdateObject> extends Array<infer W> ? Array<U | W> : TObject & ExtractTypeFromDotPathUpdateObject<TDotPathUpdateObject> : TObject & ExtractTypeFromDotPathUpdateObject<TDotPathUpdateObject>;
|
|
83
|
-
|
|
84
63
|
/** Index literal type to improve DX at managing updates. */
|
|
85
64
|
declare const LITERAL_INDEX = "${number}";
|
|
86
|
-
|
|
87
65
|
/** Primitives and browser native objects. */
|
|
88
|
-
type PrimitivesAndNativeObjects = null | undefined | string | number | boolean | symbol | bigint | Date | FileList | File;
|
|
66
|
+
type PrimitivesAndNativeObjects = null | undefined | string | number | boolean | symbol | bigint | Date | FileList | File | Blob;
|
|
89
67
|
/** Tuple type, it has to have at least property "0" */
|
|
90
68
|
type Tuple = ReadonlyArray<any> & {
|
|
91
|
-
|
|
69
|
+
"0": any;
|
|
92
70
|
};
|
|
93
71
|
/** Array indexes type. */
|
|
94
72
|
type LiteralIndex = typeof LITERAL_INDEX;
|
|
95
73
|
type ExtendedArrayIndexes = number | `${number}` | LiteralIndex;
|
|
96
|
-
/** Object Literal */
|
|
74
|
+
/** Object Literal, File and Blob still match it (they have no symbol to reject them by) */
|
|
97
75
|
type ObjectLiteral = {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
76
|
+
[x: string]: any;
|
|
77
|
+
[x: number]: any;
|
|
78
|
+
[x: symbol]: any;
|
|
79
|
+
[Symbol.iterator]?: never;
|
|
80
|
+
[Symbol.toPrimitive]?: never;
|
|
81
|
+
[Symbol.hasInstance]?: never;
|
|
82
|
+
[Symbol.unscopables]?: never;
|
|
83
|
+
[Symbol.matchAll]?: never;
|
|
84
|
+
[Symbol.toStringTag]?: never;
|
|
106
85
|
};
|
|
107
86
|
/** Strict key */
|
|
108
87
|
declare const strictSymbol: unique symbol;
|
|
109
|
-
type Strict<T> = T extends ObjectLiteral ? T & {
|
|
110
|
-
|
|
88
|
+
type Strict<T> = T extends PrimitivesAndNativeObjects ? T : T extends ObjectLiteral ? T & {
|
|
89
|
+
[strictSymbol]: DotPaths<T>;
|
|
111
90
|
} : T;
|
|
112
91
|
/** Smart KeyOf (doesnt include the "strict" key) */
|
|
113
|
-
type KeyOf<T, TAllowedValuesInKeys = any> = T extends ObjectLiteral ? T extends Strict<infer U> ? KeysOfObject<U, TAllowedValuesInKeys> : KeysOfObject<T, TAllowedValuesInKeys> : T extends Tuple ? KeysOfObject<Omit<T, keyof any[]>, TAllowedValuesInKeys> : T extends ReadonlyArray<infer U> ? U extends TAllowedValuesInKeys ? ExtendedArrayIndexes : never : never;
|
|
114
|
-
type KeysOfObject<T, TAllowedValuesInKeys> = {
|
|
115
|
-
[Key in keyof T]: T[Key] extends TAllowedValuesInKeys ? Key : never;
|
|
116
|
-
}[keyof T];
|
|
117
|
-
|
|
92
|
+
type KeyOf<T, TAllowedValuesInKeys = any> = T extends PrimitivesAndNativeObjects ? never : T extends ObjectLiteral ? T extends Strict<infer U> ? KeysOfObject<U, TAllowedValuesInKeys> : KeysOfObject<T, TAllowedValuesInKeys> : T extends Tuple ? KeysOfObject<Omit<T, keyof any[]>, TAllowedValuesInKeys> : T extends ReadonlyArray<infer U> ? U extends TAllowedValuesInKeys ? ExtendedArrayIndexes : never : never;
|
|
93
|
+
type KeysOfObject<T, TAllowedValuesInKeys> = { [Key in keyof T]-?: Required<T>[Key] extends TAllowedValuesInKeys ? Key : never; }[keyof T];
|
|
118
94
|
/** Returns only the optional keys of an object. */
|
|
119
|
-
type OptionalKeys<T> = {
|
|
120
|
-
[K in keyof T]-?: {} extends Pick<T, K> ? K : never;
|
|
121
|
-
}[keyof T];
|
|
95
|
+
type OptionalKeys<T> = { [K in keyof T]-?: {} extends Pick<T, K> ? K : never; }[keyof T];
|
|
122
96
|
/** Removes properties or indexes, order doesn't matter. */
|
|
123
97
|
type Remove = <T extends ObjectLiteral | any[]>(value: T, keys: T extends any[] ? (number | `${number}` | (number | `${number}`)[]) : OptionalKeys<T> | (OptionalKeys<T>)[]) => T;
|
|
124
98
|
/**
|
|
@@ -127,11 +101,10 @@ type Remove = <T extends ObjectLiteral | any[]>(value: T, keys: T extends any[]
|
|
|
127
101
|
* @param keys Keys to remove.
|
|
128
102
|
* @returns New object/array without the provided keys/indexes.
|
|
129
103
|
*/
|
|
130
|
-
declare const remove: Remove;
|
|
131
|
-
|
|
104
|
+
export declare const remove: Remove;
|
|
132
105
|
type Select = {
|
|
133
|
-
|
|
134
|
-
|
|
106
|
+
<T, TPath extends DotPaths<T>>(state: T, path: TPath): ReturnedValueInPath<T, TPath>;
|
|
107
|
+
<T, TPath extends ''>(state: T, path: TPath): T;
|
|
135
108
|
};
|
|
136
109
|
/**
|
|
137
110
|
* Returns the value from a given dot path of an object/array or undefined if doesn't exist.
|
|
@@ -139,8 +112,7 @@ type Select = {
|
|
|
139
112
|
* @param path Path indicating the value to extract.
|
|
140
113
|
* @returns Value of the provided path or undefined.
|
|
141
114
|
*/
|
|
142
|
-
declare const select: Select;
|
|
143
|
-
|
|
115
|
+
export declare const select: Select;
|
|
144
116
|
type PathWithoutLastKey = string;
|
|
145
117
|
type LastKey = string;
|
|
146
118
|
type SplitDotPathAtLastKey = <T extends string>(dotPath: T) => [PathWithoutLastKey, LastKey];
|
|
@@ -149,21 +121,19 @@ type SplitDotPathAtLastKey = <T extends string>(dotPath: T) => [PathWithoutLastK
|
|
|
149
121
|
* @param dotPath A dot path.
|
|
150
122
|
* @returns [pathWithoutLastKey, lastKey] or ['', lastKey].
|
|
151
123
|
*/
|
|
152
|
-
declare const splitPathAtLastKey: SplitDotPathAtLastKey;
|
|
153
|
-
|
|
124
|
+
export declare const splitPathAtLastKey: SplitDotPathAtLastKey;
|
|
154
125
|
type Set = <T>(newValue: T) => (v: unknown) => T;
|
|
155
126
|
/**
|
|
156
127
|
* Allows to set strongly typed values (removing inacurate "undefined" inference) in nested values inside arrays.
|
|
157
128
|
* @param newValue New value.
|
|
158
129
|
* @returns The same value.
|
|
159
130
|
*/
|
|
160
|
-
declare const set: Set;
|
|
161
|
-
|
|
131
|
+
export declare const set: Set;
|
|
162
132
|
type OptionValues = 'error' | 'skip' | 'add';
|
|
163
133
|
type Options = {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
134
|
+
onNewProps?: OptionValues;
|
|
135
|
+
onNewIndexes?: OptionValues;
|
|
136
|
+
onPathsIntersectedByPrimitiveValues?: OptionValues;
|
|
167
137
|
};
|
|
168
138
|
type ImmutableUpdate = <TObject, TAllowedDotPathKeys extends DotPaths<TObject> = DotPaths<TObject>>(state: TObject, dotPathUpdateObject: UpdateObject<TObject, TAllowedDotPathKeys>, options?: Options) => TObject;
|
|
169
139
|
/**
|
|
@@ -175,7 +145,7 @@ type ImmutableUpdate = <TObject, TAllowedDotPathKeys extends DotPaths<TObject> =
|
|
|
175
145
|
* @param options Options to change JS behaviour on non-existent fields.
|
|
176
146
|
* @returns New Updated Object.
|
|
177
147
|
*/
|
|
178
|
-
declare const update: ImmutableUpdate;
|
|
148
|
+
export declare const update: ImmutableUpdate;
|
|
179
149
|
type ExtendableImmutableUpdate = <TObject, TUpdateObject extends UpdateObject<TObject> = UpdateObject<TObject>>(state: TObject, dotPathUpdateObject: TUpdateObject) => ExtendedUpdate<TObject, TUpdateObject>;
|
|
180
150
|
/**
|
|
181
151
|
* Creates a new object applying immutable updates using dot-path syntax.
|
|
@@ -185,26 +155,21 @@ type ExtendableImmutableUpdate = <TObject, TUpdateObject extends UpdateObject<TO
|
|
|
185
155
|
* @param dotPathUpdateObject Dot Path Update Object.
|
|
186
156
|
* @returns New Updated Object.
|
|
187
157
|
*/
|
|
188
|
-
declare const experimental_extendableUpdate: ExtendableImmutableUpdate;
|
|
189
|
-
|
|
158
|
+
export declare const experimental_extendableUpdate: ExtendableImmutableUpdate;
|
|
190
159
|
type ForEachEntry = <T extends ObjectLiteral>(object: T, callbackfn: (key: keyof T, value: T[keyof T]) => void) => void;
|
|
191
|
-
declare const forEachEntry: ForEachEntry;
|
|
192
|
-
|
|
160
|
+
export declare const forEachEntry: ForEachEntry;
|
|
193
161
|
/** Checks if any provided value is an object literal or not */
|
|
194
162
|
type IsObjectLiteral = (valueToTest: unknown) => valueToTest is ObjectLiteral;
|
|
195
|
-
declare const isObjectLiteral: IsObjectLiteral;
|
|
196
|
-
|
|
163
|
+
export declare const isObjectLiteral: IsObjectLiteral;
|
|
197
164
|
/** Adds strict property to an object literal */
|
|
198
165
|
type StrictFn = <T>(value: T) => Strict<T>;
|
|
199
|
-
declare const strict: StrictFn;
|
|
200
|
-
declare const s: StrictFn;
|
|
166
|
+
export declare const strict: StrictFn;
|
|
167
|
+
export declare const s: StrictFn;
|
|
201
168
|
/** Checks the strictness of a type passed to a function or callback without 3rd party implementation */
|
|
202
|
-
type
|
|
203
|
-
declare const
|
|
204
|
-
|
|
169
|
+
type StrictType = <T extends U, U>(v: T extends U ? DotPaths<T> extends DotPaths<U> ? T : Exclude<DotPaths<T>, DotPaths<U>> : never) => U;
|
|
170
|
+
export declare const strictType: StrictType;
|
|
205
171
|
type ParseStringIndex = (stringKey: string) => number | null;
|
|
206
|
-
declare const parseStringIndex: ParseStringIndex;
|
|
172
|
+
export declare const parseStringIndex: ParseStringIndex;
|
|
207
173
|
type IsStringIndex = (stringKey: string) => stringKey is `${number}`;
|
|
208
|
-
declare const isStringIndex: IsStringIndex;
|
|
209
|
-
|
|
210
|
-
export { type DotPaths, type ExtendedArrayIndexes, type KeyOf, type LiteralIndex, type ObjectLiteral, type PrimitivesAndNativeObjects, type ReturnedValueInPath, type Strict, type Tuple, type UpdateObject, type UpdateValue, type ValueInPath, experimental_extendableUpdate, forEachEntry, isObjectLiteral, isStringIndex, parseStringIndex, remove, s, select, set, splitPathAtLastKey, strict, strictValueWrapper, update };
|
|
174
|
+
export declare const isStringIndex: IsStringIndex;
|
|
175
|
+
export type { DotPaths, ExtendedArrayIndexes, KeyOf, LiteralIndex, ObjectLiteral, PrimitivesAndNativeObjects, ReturnedValueInPath, Strict, Tuple, UpdateObject, UpdateValue, ValueInPath };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=e=>!!e&&Object.getPrototypeOf(e)===Object.prototype,t=(t,n)=>{if(!Array.isArray(t)&&!e(t))throw`Wrong type provided in "remove" function`;let r=Array.isArray(n)?n:[n];if(Array.isArray(t)){let e=Symbol(),n=[...t];return r.forEach(t=>{n[t]=e}),n.filter(t=>t!==e)}let i={...t};return r.forEach(e=>delete i[e]),i},n=(e,t)=>{if(typeof t!=`string`)throw Error(`path is not a string`);if(!t)return e;let n=t.split(`.`),r=e;for(;n.length;){if(r==null)return;let e=n[0],t=n.join(`.`);if(Object.hasOwn(r,t))return r[t];if(!Object.hasOwn(r,e))return;r=r[e],n.shift()}return r},r=e=>{if(typeof e!=`string`)throw Error(`Wrong dotPath type: ${e}`);let t=e.lastIndexOf(`.`)+1;return[t?e.slice(0,t-1):``,e.slice(t)]},i=e=>()=>e,a=e=>{let t=parseInt(e);return e!==`NaN`&&t.toString()===e?t:null},o=e=>e!==`NaN`&&parseInt(e).toString()===e,s=e=>JSON.stringify(e),c=e=>Array.isArray(e),l=(t,n,r={})=>{if(!e(t)&&!c(t))throw Error(`"${s(t)}" is not an literalObject/array`);if(!e(n))throw Error(`wrong "updateObject" type provided`);let i=Array.isArray(t)?[...t]:{...t},a=Object.create(null),l=Object.entries(n),u=l.length===1;nextUpdate:for(let[t,n]of l){if(t===``)continue;let l=t.split(`.`),d=a;if(l.includes(`__proto__`))throw Error(`"__proto__" is not allowed in "${t}"`);let f=i,p=l[l.length-1],m=0;for(let n=0;n<l.length-1;n++){let i=t.slice(m);if(Object.hasOwn(f,i)){p=i;break}let a=l[n],s=Object.hasOwn(f,a)?f[a]:void 0;m+=a.length+1;let h=d[a];if(h){f=s,d=h;continue}let g=e(s),_=c(s);if(!g&&!_&&s!==void 0){if(r.onPathsIntersectedByPrimitiveValues===`error`)throw Error(`Property "${a}" in "${t}" is a primitive`);if(r.onPathsIntersectedByPrimitiveValues===`skip`)continue nextUpdate}if(!g&&!_){let e=c(f)&&o(a),i=o(l[n+1]),s=e?r.onNewIndexes:r.onNewProps;if(s===`error`)throw Error(`${a} doesn't exist in "${t}"`);if(s===`skip`)continue nextUpdate;f[a]=i?[]:{}}else f[a]=_?[...s]:{...s};f=f[a],!u&&(d[a]=Object.create(null),d=d[a])}let h=f,g=!Object.hasOwn(h,p);if(g){let e=c(h)&&o(p)?r.onNewIndexes:r.onNewProps;if(e===`error`)throw Error(`Property/Index "${p}" doesnt exist in the path "${t}". Its value is: "${s(h)}"`);if(e===`skip`)continue}let _=g?void 0:h[p];h[p]=typeof n==`function`?n(_):n,delete d[p]}return i},u=(e,t,n)=>l(e,t,n),d=(e,t)=>l(e,t),f=(e,t)=>Object.keys(e).forEach(n=>t(n,e[n])),p=e=>e,m=p,h=e=>e;exports.experimental_extendableUpdate=d,exports.forEachEntry=f,exports.isObjectLiteral=e,exports.isStringIndex=o,exports.parseStringIndex=a,exports.remove=t,exports.s=m,exports.select=n,exports.set=i,exports.splitPathAtLastKey=r,exports.strict=p,exports.strictType=h,exports.update=u;
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
const e=e=>!!e&&Object.getPrototypeOf(e)===Object.prototype,t=(t,n)=>{if(!Array.isArray(t)&&!e(t))throw`Wrong type provided in "remove" function`;let r=Array.isArray(n)?n:[n];if(Array.isArray(t)){let e=Symbol(),n=[...t];return r.forEach(t=>{n[t]=e}),n.filter(t=>t!==e)}let i={...t};return r.forEach(e=>delete i[e]),i},n=(e,t)=>{if(typeof t!=`string`)throw Error(`path is not a string`);if(!t)return e;let n=t.split(`.`),r=e;for(;n.length;){if(r==null)return;let e=n[0],t=n.join(`.`);if(Object.hasOwn(r,t))return r[t];if(!Object.hasOwn(r,e))return;r=r[e],n.shift()}return r},r=e=>{if(typeof e!=`string`)throw Error(`Wrong dotPath type: ${e}`);let t=e.lastIndexOf(`.`)+1;return[t?e.slice(0,t-1):``,e.slice(t)]},i=e=>()=>e,a=e=>{let t=parseInt(e);return e!==`NaN`&&t.toString()===e?t:null},o=e=>e!==`NaN`&&parseInt(e).toString()===e,s=e=>JSON.stringify(e),c=e=>Array.isArray(e),l=(t,n,r={})=>{if(!e(t)&&!c(t))throw Error(`"${s(t)}" is not an literalObject/array`);if(!e(n))throw Error(`wrong "updateObject" type provided`);let i=Array.isArray(t)?[...t]:{...t},a=Object.create(null),l=Object.entries(n),u=l.length===1;nextUpdate:for(let[t,n]of l){if(t===``)continue;let l=t.split(`.`),d=a;if(l.includes(`__proto__`))throw Error(`"__proto__" is not allowed in "${t}"`);let f=i,p=l[l.length-1],m=0;for(let n=0;n<l.length-1;n++){let i=t.slice(m);if(Object.hasOwn(f,i)){p=i;break}let a=l[n],s=Object.hasOwn(f,a)?f[a]:void 0;m+=a.length+1;let h=d[a];if(h){f=s,d=h;continue}let g=e(s),_=c(s);if(!g&&!_&&s!==void 0){if(r.onPathsIntersectedByPrimitiveValues===`error`)throw Error(`Property "${a}" in "${t}" is a primitive`);if(r.onPathsIntersectedByPrimitiveValues===`skip`)continue nextUpdate}if(!g&&!_){let e=c(f)&&o(a),i=o(l[n+1]),s=e?r.onNewIndexes:r.onNewProps;if(s===`error`)throw Error(`${a} doesn't exist in "${t}"`);if(s===`skip`)continue nextUpdate;f[a]=i?[]:{}}else f[a]=_?[...s]:{...s};f=f[a],!u&&(d[a]=Object.create(null),d=d[a])}let h=f,g=!Object.hasOwn(h,p);if(g){let e=c(h)&&o(p)?r.onNewIndexes:r.onNewProps;if(e===`error`)throw Error(`Property/Index "${p}" doesnt exist in the path "${t}". Its value is: "${s(h)}"`);if(e===`skip`)continue}let _=g?void 0:h[p];h[p]=typeof n==`function`?n(_):n,delete d[p]}return i},u=(e,t,n)=>l(e,t,n),d=(e,t)=>l(e,t),f=(e,t)=>Object.keys(e).forEach(n=>t(n,e[n])),p=e=>e,m=p,h=e=>e;export{d as experimental_extendableUpdate,f as forEachEntry,e as isObjectLiteral,o as isStringIndex,a as parseStringIndex,t as remove,m as s,n as select,i as set,r as splitPathAtLastKey,p as strict,h as strictType,u as update};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "maraj",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "A lightweight
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "A lightweight (~1.2 KB gzipped) alternative for immutable updates while dealing with objects and arrays",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"shallow",
|
|
7
7
|
"shallow copy",
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
"scripts": {
|
|
22
22
|
"dev": "vitest",
|
|
23
23
|
"test": "vitest run",
|
|
24
|
-
"build": "
|
|
24
|
+
"build": "tsdown",
|
|
25
25
|
"lint": "tsc",
|
|
26
26
|
"trace": "tsc --generateTrace trace",
|
|
27
27
|
"ci": "npm run lint && npm run test && npm run build",
|
|
28
|
-
"release": "
|
|
28
|
+
"release": "node scripts/check-changelog.mjs && npm run build && changeset publish"
|
|
29
29
|
},
|
|
30
30
|
"repository": {
|
|
31
31
|
"type": "git",
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
},
|
|
37
37
|
"homepage": "https://github.com/Lukasz17git/maraj#readme",
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@changesets/cli": "^
|
|
40
|
-
"@microsoft/api-extractor": "^7.
|
|
41
|
-
"@typescript/analyze-trace": "^0.
|
|
42
|
-
"
|
|
43
|
-
"typescript": "^
|
|
44
|
-
"vitest": "^0.
|
|
39
|
+
"@changesets/cli": "^3.0.3",
|
|
40
|
+
"@microsoft/api-extractor": "^7.59.4",
|
|
41
|
+
"@typescript/analyze-trace": "^0.11.1",
|
|
42
|
+
"tsdown": "^0.23.1",
|
|
43
|
+
"typescript": "^7.0.2",
|
|
44
|
+
"vitest": "^5.0.5"
|
|
45
45
|
}
|
|
46
46
|
}
|