@rimbu/deep 2.0.1 → 2.0.3
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 +295 -60
- package/dist/bun/deep.mts +8 -8
- package/dist/bun/match.mts +29 -27
- package/dist/bun/patch.mts +11 -10
- package/dist/bun/path.mts +98 -100
- package/dist/bun/protected.mts +18 -17
- package/dist/bun/selector.mts +22 -20
- package/dist/bun/tuple.mts +6 -2
- package/dist/cjs/deep.cjs +18 -18
- package/dist/cjs/deep.cjs.map +1 -1
- package/dist/cjs/deep.d.cts +6 -6
- package/dist/cjs/match.cjs +2 -3
- package/dist/cjs/match.cjs.map +1 -1
- package/dist/cjs/match.d.cts +2 -2
- package/dist/cjs/patch.cjs +2 -3
- package/dist/cjs/patch.cjs.map +1 -1
- package/dist/cjs/patch.d.cts +1 -1
- package/dist/cjs/path.cjs +5 -5
- package/dist/cjs/path.cjs.map +1 -1
- package/dist/cjs/path.d.cts +8 -6
- package/dist/cjs/selector.cjs +1 -2
- package/dist/cjs/selector.cjs.map +1 -1
- package/dist/cjs/tuple.cjs +1 -1
- package/dist/cjs/tuple.cjs.map +1 -1
- package/dist/cjs/tuple.d.cts +5 -1
- package/dist/esm/deep.d.mts +6 -6
- package/dist/esm/deep.mjs +6 -6
- package/dist/esm/match.d.mts +2 -2
- package/dist/esm/match.mjs +1 -1
- package/dist/esm/match.mjs.map +1 -1
- package/dist/esm/patch.d.mts +1 -1
- package/dist/esm/patch.mjs +1 -1
- package/dist/esm/patch.mjs.map +1 -1
- package/dist/esm/path.d.mts +8 -6
- package/dist/esm/path.mjs +2 -2
- package/dist/esm/path.mjs.map +1 -1
- package/dist/esm/selector.mjs.map +1 -1
- package/dist/esm/tuple.d.mts +5 -1
- package/dist/esm/tuple.mjs +1 -1
- package/dist/esm/tuple.mjs.map +1 -1
- package/package.json +7 -7
- package/src/deep.mts +8 -8
- package/src/match.mts +29 -27
- package/src/patch.mts +11 -10
- package/src/path.mts +98 -100
- package/src/protected.mts +18 -17
- package/src/selector.mts +22 -20
- package/src/tuple.mts +6 -2
package/README.md
CHANGED
|
@@ -1,112 +1,347 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
|
|
2
|
+
<img src="https://github.com/rimbu-org/rimbu/raw/main/assets/rimbu_logo.svg" height="96" alt="Rimbu Logo" />
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
<div align="center">
|
|
6
6
|
|
|
7
|
-
](https://www.npmjs.com/package/@rimbu/deep)
|
|
8
|
+

|
|
9
|
+

|
|
10
|
+

|
|
11
|
+

|
|
12
|
+

|
|
13
|
+

|
|
8
14
|
|
|
9
|
-
|
|
15
|
+
</div>
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
# `@rimbu/deep`
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
**Immutable, type-safe utilities for deeply patching, matching, and selecting from plain JavaScript objects.**
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
`@rimbu/deep` gives you a set of composable tools – `Patch`, `Match`, `Path`, `Selector`, `Protected`, and `Tuple` –
|
|
22
|
+
to treat plain objects as if they were immutable, deeply typed data structures. You can:
|
|
16
23
|
|
|
17
|
-
|
|
24
|
+
- **Apply immutable updates** to nested structures using a flexible `Patch` notation.
|
|
25
|
+
- **Express rich match conditions** over objects and arrays using `Match`.
|
|
26
|
+
- **Access nested properties safely** using type‑checked string `Path`s.
|
|
27
|
+
- **Build typed projections** from objects using `Selector` shapes.
|
|
28
|
+
- **Protect values at compile time** from accidental mutation using `Protected`.
|
|
29
|
+
- **Work ergonomically with tuples** and fixed‑length arrays via `Tuple`.
|
|
18
30
|
|
|
19
|
-
|
|
31
|
+
Use it whenever you want the convenience of plain objects, but with **deep type safety**, **immutable semantics**, and
|
|
32
|
+
**refactor‑friendly string paths**.
|
|
20
33
|
|
|
21
|
-
|
|
22
|
-
- [`Deno` ](https://deno.com/runtime)
|
|
23
|
-
- [`Bun >= 0.6.0` ](https://bun.sh/)
|
|
24
|
-
- `Web` 
|
|
34
|
+
---
|
|
25
35
|
|
|
26
|
-
|
|
36
|
+
## Table of Contents
|
|
27
37
|
|
|
28
|
-
|
|
38
|
+
1. [Why `@rimbu/deep`?](#why-rimbu-deep)
|
|
39
|
+
2. [Feature Highlights](#feature-highlights)
|
|
40
|
+
3. [Quick Start](#quick-start)
|
|
41
|
+
4. [Core Concepts & Types](#core-concepts--types)
|
|
42
|
+
5. [Deep API Helpers](#deep-api-helpers)
|
|
43
|
+
6. [Installation](#installation)
|
|
44
|
+
7. [Ecosystem & Further Reading](#ecosystem--further-reading)
|
|
45
|
+
8. [Contributing](#contributing)
|
|
46
|
+
9. [License](#license)
|
|
29
47
|
|
|
30
|
-
|
|
48
|
+
---
|
|
31
49
|
|
|
32
|
-
|
|
50
|
+
## Why `@rimbu/deep`?
|
|
33
51
|
|
|
34
|
-
|
|
52
|
+
Plain objects are great, but they quickly become painful when:
|
|
35
53
|
|
|
36
|
-
|
|
54
|
+
- You need to **update nested fields immutably** (e.g. in Redux‑style state).
|
|
55
|
+
- You want **type‑safe string paths** like `'a.b.c[0]?.d'` instead of ad‑hoc helpers.
|
|
56
|
+
- You’d like to **pattern‑match** complex structures without a forest of `if`/`switch` checks.
|
|
57
|
+
- You want to **project and reshape data** (e.g. API responses) into well‑typed views.
|
|
37
58
|
|
|
38
|
-
|
|
59
|
+
`@rimbu/deep` focuses on:
|
|
39
60
|
|
|
40
|
-
|
|
61
|
+
- **Type‑driven paths and selectors** – `Path` and `Selector` are derived from your data types.
|
|
62
|
+
- **Immutable patching** – `Patch` lets you describe updates declaratively and apply them in one go.
|
|
63
|
+
- **Expressive matching** – `Match` supports nested objects, arrays, tuples, and compound predicates.
|
|
64
|
+
- **Compile‑time protection** – `Protected<T>` makes entire object graphs appear readonly to TypeScript.
|
|
41
65
|
|
|
42
|
-
|
|
66
|
+
If you find yourself writing a lot of manual cloning, deep property access, or matcher utilities, `@rimbu/deep` is a
|
|
67
|
+
drop‑in improvement.
|
|
43
68
|
|
|
44
|
-
|
|
69
|
+
---
|
|
45
70
|
|
|
46
|
-
|
|
71
|
+
## Feature Highlights
|
|
47
72
|
|
|
48
|
-
|
|
73
|
+
- **Deep immutable patching** with `patch` and `patchAt`:
|
|
74
|
+
describe updates using nested objects/arrays and functions instead of manual cloning.
|
|
75
|
+
- **Typed string paths** with `Path.Get` and `Path.Set`:
|
|
76
|
+
only valid paths for your data type compile.
|
|
77
|
+
- **Structured matching** with `match`:
|
|
78
|
+
supports nested objects, tuple/array traversal, and compound matchers (`every`, `some`, `none`, `single`).
|
|
79
|
+
- **Selection & projection** with `select` and `Selector`:
|
|
80
|
+
derive new shapes from existing data using path strings, functions, or nested selector objects.
|
|
81
|
+
- **Compile‑time protection** with `Protected` and `protect`:
|
|
82
|
+
make values deeply readonly at the type level while still using the underlying runtime value.
|
|
83
|
+
- **Tuple helpers** with `Tuple`:
|
|
84
|
+
ergonomics around fixed‑length tuples (construction, indexing, updates, etc.).
|
|
49
85
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Quick Start
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
import { Deep } from '@rimbu/deep';
|
|
92
|
+
|
|
93
|
+
const input = { a: 1, b: { c: true, d: 'a' } } as const;
|
|
94
|
+
|
|
95
|
+
// Immutable deep patch
|
|
96
|
+
const updated = Deep.patch(input, [{ b: [{ c: (v) => !v }] }]);
|
|
97
|
+
// => { a: 1, b: { c: false, d: 'a' } }
|
|
98
|
+
|
|
99
|
+
// Type-safe nested get
|
|
100
|
+
const cValue = Deep.getAt(input, 'b.c'); // boolean
|
|
101
|
+
|
|
102
|
+
// Pattern matching
|
|
103
|
+
if (Deep.match(input, { b: { c: true } })) {
|
|
104
|
+
// ...
|
|
55
105
|
}
|
|
106
|
+
|
|
107
|
+
// Selection / projection
|
|
108
|
+
const projected = Deep.select(input, { flag: 'b.c', label: 'b.d' });
|
|
109
|
+
// projected: { flag: boolean; label: string }
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Try Rimbu (including `@rimbu/deep`) live in the browser using the
|
|
113
|
+
[Rimbu Sandbox on CodeSandbox](https://codesandbox.io/s/github/vitoke/rimbu-sandbox/tree/main?previewwindow=console&view=split&editorsize=65&moduleview=1&module=/src/index.ts).
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Core Concepts & Types
|
|
118
|
+
|
|
119
|
+
### Exported Types & Namespaces
|
|
120
|
+
|
|
121
|
+
From `@rimbu/deep`’s main entrypoint you have access to:
|
|
122
|
+
|
|
123
|
+
| Name | Description |
|
|
124
|
+
| ---------------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
125
|
+
| `Patch<T, C = T>` | Type describing allowed patch shapes for a value of type `T`. |
|
|
126
|
+
| `Match<T, C = Partial<T>>` | Type describing allowed matchers for values of type `T`. |
|
|
127
|
+
| `Path` | Namespace containing `Path.Get<T>`, `Path.Set<T>`, and `Path.Result<T, P>` utilities for string paths. |
|
|
128
|
+
| `Selector<T>` | Type describing allowed selector shapes for values of type `T`. |
|
|
129
|
+
| `Protected<T>` | Deeply readonly/“protected” view of `T` for compile‑time mutation safety. |
|
|
130
|
+
| `Tuple<T extends Tuple.Source>` | Tuple wrapper with helper types and functions under the `Tuple` namespace. |
|
|
131
|
+
| `Deep` | Convenience namespace exposing the main deep utilities (`patch`, `match`, `getAt`, `select`, etc.). |
|
|
132
|
+
|
|
133
|
+
See the [Deep overview docs](https://rimbu.org/docs/deep/overview) and
|
|
134
|
+
[API reference](https://rimbu.org/api/rimbu/deep) for the full surface.
|
|
135
|
+
|
|
136
|
+
### Patching with `patch` and `Patch`
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
import { Deep, type Patch } from '@rimbu/deep';
|
|
140
|
+
|
|
141
|
+
type State = {
|
|
142
|
+
count: number;
|
|
143
|
+
user?: { name: string; active: boolean };
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const state: State = { count: 1, user: { name: 'Ada', active: true } };
|
|
147
|
+
|
|
148
|
+
const patchItem: Patch<State> = [
|
|
149
|
+
{ count: (v) => v + 1 },
|
|
150
|
+
{ user: [{ active: false }] },
|
|
151
|
+
];
|
|
152
|
+
|
|
153
|
+
const next = Deep.patch(state, patchItem);
|
|
154
|
+
// => { count: 2, user: { name: 'Ada', active: false } }
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Patches can be:
|
|
158
|
+
|
|
159
|
+
- Direct replacement values (`T`).
|
|
160
|
+
- Functions `(current, parent, root) => newValue`.
|
|
161
|
+
- Nested objects / arrays describing which fields or tuple indices to update.
|
|
162
|
+
|
|
163
|
+
### Matching with `match` and `Match`
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
import { Deep, type Match } from '@rimbu/deep';
|
|
167
|
+
|
|
168
|
+
type Item = { id: number; tags: string[] };
|
|
169
|
+
|
|
170
|
+
const items: Item[] = [
|
|
171
|
+
{ id: 1, tags: ['a', 'b'] },
|
|
172
|
+
{ id: 2, tags: ['b'] },
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
const matcher: Match<Item> = {
|
|
176
|
+
tags: { someItem: (tag) => tag === 'a' },
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const result = items.filter((item) => Deep.match(item, matcher));
|
|
180
|
+
// => only items containing tag 'a'
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
`Match` supports:
|
|
184
|
+
|
|
185
|
+
- Plain object matchers (`{ a: 1, b: { c: true } }`).
|
|
186
|
+
- Function matchers `(value, parent, root) => boolean | matcher`.
|
|
187
|
+
- Array/tuple matchers and traversal helpers such as `someItem`, `everyItem`, `noneItem`, `singleItem`.
|
|
188
|
+
- Compound matchers like `['every', matcher1, matcher2]`.
|
|
189
|
+
|
|
190
|
+
### Paths with `Path.Get`, `Path.Set` and `getAt` / `patchAt`
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
import { Deep, type Path } from '@rimbu/deep';
|
|
194
|
+
|
|
195
|
+
type Model = { a: { b: { c: number }[] } };
|
|
196
|
+
const value: Model = { a: { b: { c: [5, 6] } } as any };
|
|
197
|
+
|
|
198
|
+
// Typed paths
|
|
199
|
+
const path: Path.Get<Model> = 'a.b.c[1]?.d'; // compile-time checked
|
|
200
|
+
|
|
201
|
+
// Reading
|
|
202
|
+
const result = Deep.getAt(value, 'a.b.c[0]'); // number | undefined
|
|
203
|
+
|
|
204
|
+
// Patching at a path
|
|
205
|
+
const updated = Deep.patchAt(value, 'a.b.c', (arr) => [...arr, 7]);
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
`Path.Result<T, P>` gives you the resulting type at a given path `P` in `T`.
|
|
209
|
+
|
|
210
|
+
### Selection with `Selector` and `select`
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
import { Deep, type Selector } from '@rimbu/deep';
|
|
214
|
+
|
|
215
|
+
type Source = {
|
|
216
|
+
a: { b: number; c: string };
|
|
217
|
+
meta: { createdAt: string };
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
const source: Source = {
|
|
221
|
+
a: { b: 1, c: 'x' },
|
|
222
|
+
meta: { createdAt: '2024-01-01' },
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const selector: Selector<Source> = {
|
|
226
|
+
value: 'a.b',
|
|
227
|
+
label: 'a.c',
|
|
228
|
+
created: 'meta.createdAt',
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const view = Deep.select(source, selector);
|
|
232
|
+
// view: { value: number; label: string; created: string }
|
|
56
233
|
```
|
|
57
234
|
|
|
58
|
-
|
|
235
|
+
Selectors can be:
|
|
236
|
+
|
|
237
|
+
- String paths.
|
|
238
|
+
- Functions `(value: Protected<T>) => any`.
|
|
239
|
+
- Arrays or objects composed of other selectors.
|
|
59
240
|
|
|
60
|
-
|
|
241
|
+
### Protection with `Protected` and `protect`
|
|
61
242
|
|
|
62
243
|
```ts
|
|
63
|
-
import {
|
|
64
|
-
|
|
244
|
+
import { Deep, type Protected } from '@rimbu/deep';
|
|
245
|
+
|
|
246
|
+
type Data = { a: { b: number[] } };
|
|
247
|
+
|
|
248
|
+
const data: Data = { a: { b: [1, 2] } };
|
|
249
|
+
const protectedData: Protected<Data> = Deep.protect(data);
|
|
250
|
+
|
|
251
|
+
// protectedData.a.b.push(3); // TypeScript error – `b` is readonly
|
|
65
252
|
```
|
|
66
253
|
|
|
67
|
-
|
|
254
|
+
`Protected<T>` is a **type‑level** construct: it does not freeze the value at runtime, but helps prevent
|
|
255
|
+
accidental mutations in your code.
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Deep API Helpers
|
|
260
|
+
|
|
261
|
+
All top‑level utilities are also available through the `Deep` namespace:
|
|
68
262
|
|
|
69
263
|
```ts
|
|
70
|
-
import {
|
|
264
|
+
import { Deep } from '@rimbu/deep';
|
|
265
|
+
|
|
266
|
+
// Functional helpers
|
|
267
|
+
const incCount = Deep.patchWith<{ count: number }>([{ count: (v) => v + 1 }]);
|
|
268
|
+
const onlyActive = Deep.matchWith({ active: true });
|
|
269
|
+
const getName = Deep.getAtWith<{ user: { name: string } }>('user.name');
|
|
270
|
+
|
|
271
|
+
// Typed, curried API with withType
|
|
272
|
+
const s = { a: 1, b: { c: 'a', d: true } };
|
|
273
|
+
const api = Deep.withType<typeof s>();
|
|
274
|
+
|
|
275
|
+
const next = api.patchWith([{ b: [{ d: (v) => !v }] }])(s);
|
|
276
|
+
// => { a: 1, b: { c: 'a', d: false } }
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
The `Deep` namespace mirrors the main exports:
|
|
280
|
+
|
|
281
|
+
- `Deep.patch`, `Deep.patchAt`, `Deep.patchWith`, `Deep.patchAtWith`
|
|
282
|
+
- `Deep.match`, `Deep.matchAt`, `Deep.matchWith`, `Deep.matchAtWith`
|
|
283
|
+
- `Deep.getAt`, `Deep.getAtWith`
|
|
284
|
+
- `Deep.select`, `Deep.selectAt`, `Deep.selectWith`, `Deep.selectAtWith`
|
|
285
|
+
- `Deep.withType<T>()` for creating a typed, curried API.
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Installation
|
|
290
|
+
|
|
291
|
+
### Node / Bun / npm / Yarn
|
|
292
|
+
|
|
293
|
+
```sh
|
|
294
|
+
npm install @rimbu/deep
|
|
295
|
+
# or
|
|
296
|
+
yarn add @rimbu/deep
|
|
297
|
+
# or
|
|
298
|
+
bun add @rimbu/deep
|
|
71
299
|
```
|
|
72
300
|
|
|
73
|
-
|
|
301
|
+
### Deno (import map)
|
|
74
302
|
|
|
75
|
-
|
|
303
|
+
```jsonc
|
|
304
|
+
{
|
|
305
|
+
"imports": {
|
|
306
|
+
"@rimbu/": "https://deno.land/x/rimbu@<version>/"
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
```
|
|
76
310
|
|
|
77
|
-
|
|
311
|
+
Then:
|
|
78
312
|
|
|
79
313
|
```ts
|
|
80
|
-
import {
|
|
81
|
-
|
|
82
|
-
console.log(
|
|
83
|
-
patch({
|
|
84
|
-
a: 'a',
|
|
85
|
-
b: { c: 1, d: true },
|
|
86
|
-
})({
|
|
87
|
-
a: 'q',
|
|
88
|
-
b: { c: (v) => v + 1 },
|
|
89
|
-
})
|
|
90
|
-
);
|
|
91
|
-
// => { a: 'q', b: { c: 2, d: true }}
|
|
314
|
+
import { Deep } from '@rimbu/deep/mod.ts';
|
|
92
315
|
```
|
|
93
316
|
|
|
94
|
-
|
|
317
|
+
### Browser / ESM
|
|
95
318
|
|
|
96
|
-
|
|
319
|
+
`@rimbu/deep` ships both **ESM** and **CJS** builds. Use it with any modern bundler
|
|
320
|
+
(Vite, Webpack, esbuild, Bun, etc.) or directly in Node ESM projects.
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## Ecosystem & Further Reading
|
|
325
|
+
|
|
326
|
+
- Part of the broader **Rimbu** ecosystem – interoperates with `@rimbu/core`, `@rimbu/collection-types`,
|
|
327
|
+
and other collection packages.
|
|
328
|
+
- Ideal for modelling immutable application state, selectors, and matchers in complex domains.
|
|
329
|
+
- Learn more in the [Deep overview docs](https://rimbu.org/docs/deep/overview) and the
|
|
330
|
+
[Deep API reference](https://rimbu.org/api/rimbu/deep).
|
|
331
|
+
|
|
332
|
+
---
|
|
97
333
|
|
|
98
334
|
## Contributing
|
|
99
335
|
|
|
100
|
-
|
|
336
|
+
We welcome contributions! See the
|
|
337
|
+
[Contributing guide](https://github.com/rimbu-org/rimbu/blob/main/CONTRIBUTING.md) for details.
|
|
101
338
|
|
|
102
|
-
|
|
339
|
+
<img src="https://contrib.rocks/image?repo=rimbu-org/rimbu" alt="Contributors" />
|
|
103
340
|
|
|
104
|
-
|
|
341
|
+
_Made with [contributors-img](https://contrib.rocks)._
|
|
105
342
|
|
|
106
|
-
|
|
343
|
+
---
|
|
107
344
|
|
|
108
345
|
## License
|
|
109
346
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
See [LICENSE](./LICENSE) for more information.
|
|
347
|
+
MIT © Rimbu contributors. See [LICENSE](./LICENSE) for details.
|
package/dist/bun/deep.mts
CHANGED
|
@@ -90,9 +90,9 @@ export function patchAtWith<T, P extends Path.Set<T>, TE extends T = T, TT = T>(
|
|
|
90
90
|
|
|
91
91
|
/**
|
|
92
92
|
* Returns a function that matches a given `value` with the given `matcher`.
|
|
93
|
-
* @typeparam T - the
|
|
93
|
+
* @typeparam T - the input value type
|
|
94
94
|
* @param matcher - a matcher object that matches input values.
|
|
95
|
-
* @param source - the value to
|
|
95
|
+
* @param source - the value to match (parameter of the returned function).
|
|
96
96
|
* @example
|
|
97
97
|
* ```ts
|
|
98
98
|
* const items = [{ a: 1, b: 'a' }, { a: 2, b: 'b' }];
|
|
@@ -128,7 +128,7 @@ export function matchAt<T, P extends Path.Get<T>>(
|
|
|
128
128
|
|
|
129
129
|
/**
|
|
130
130
|
* Returns a function that matches a given `value` with the given `matcher` at the given string `path`.
|
|
131
|
-
* @typeparam T - the
|
|
131
|
+
* @typeparam T - the input value type
|
|
132
132
|
* @typeparam P - the string literal path type in the object
|
|
133
133
|
* @typeparam TE - utility type
|
|
134
134
|
* @param path - the string path in the object
|
|
@@ -150,7 +150,7 @@ export function matchAtWith<T, P extends Path.Get<T>, TE extends T = T>(
|
|
|
150
150
|
|
|
151
151
|
/**
|
|
152
152
|
* Returns a function that selects a certain shape from a given `value` with the given `selector`.
|
|
153
|
-
* @typeparam T - the
|
|
153
|
+
* @typeparam T - the input value type
|
|
154
154
|
* @typeparam SL - the selector shape type
|
|
155
155
|
* @param selector - a shape indicating the selection from the source values
|
|
156
156
|
* @param source - the value to use the given `selector` on.
|
|
@@ -169,7 +169,7 @@ export function selectWith<T, SL extends Selector<T>>(
|
|
|
169
169
|
|
|
170
170
|
/**
|
|
171
171
|
* Returns the result of applying the given `selector` shape to the given `source` value.
|
|
172
|
-
* @typeparam T - the
|
|
172
|
+
* @typeparam T - the input value type
|
|
173
173
|
* @typeparam P - the string literal path type in the object
|
|
174
174
|
* @typeparam SL - the selector shape type
|
|
175
175
|
* @param source - the source value to select from
|
|
@@ -185,7 +185,7 @@ export function selectWith<T, SL extends Selector<T>>(
|
|
|
185
185
|
export function selectAt<
|
|
186
186
|
T,
|
|
187
187
|
P extends Path.Get<T>,
|
|
188
|
-
SL extends Selector<Path.Result<T, P
|
|
188
|
+
SL extends Selector<Path.Result<T, P>>,
|
|
189
189
|
>(
|
|
190
190
|
source: T,
|
|
191
191
|
path: P,
|
|
@@ -196,7 +196,7 @@ export function selectAt<
|
|
|
196
196
|
|
|
197
197
|
/**
|
|
198
198
|
* Returns a function that selects a certain shape from a given `value` with the given `selector` at the given string `path`.
|
|
199
|
-
* @typeparam T - the
|
|
199
|
+
* @typeparam T - the input value type
|
|
200
200
|
* @typeparam P - the string literal path type in the object
|
|
201
201
|
* @typeparam SL - the selector shape type
|
|
202
202
|
* @param path - the string path in the object
|
|
@@ -211,7 +211,7 @@ export function selectAt<
|
|
|
211
211
|
export function selectAtWith<
|
|
212
212
|
T,
|
|
213
213
|
P extends Path.Get<T>,
|
|
214
|
-
SL extends Selector<Path.Result<T, P
|
|
214
|
+
SL extends Selector<Path.Result<T, P>>,
|
|
215
215
|
>(
|
|
216
216
|
path: P,
|
|
217
217
|
selector: Selector.Shape<SL>
|
package/dist/bun/match.mts
CHANGED
|
@@ -28,25 +28,31 @@ export namespace Match {
|
|
|
28
28
|
* @typeparam P - the parent type
|
|
29
29
|
* @typeparam R - the root object type
|
|
30
30
|
*/
|
|
31
|
-
export type Entry<T, C, P, R> =
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
| Match.Entry<T[number & keyof T], C[number & keyof C], P, R>[]
|
|
41
|
-
| Match.Func<
|
|
42
|
-
T,
|
|
43
|
-
P,
|
|
44
|
-
R,
|
|
31
|
+
export type Entry<T, C, P, R> =
|
|
32
|
+
IsAnyFunc<T> extends true
|
|
33
|
+
? // function can only be directly matched
|
|
34
|
+
T
|
|
35
|
+
: IsPlainObj<T> extends true
|
|
36
|
+
? // determine allowed match values for object
|
|
37
|
+
Match.WithResult<T, P, R, Match.Obj<T, C, P, R>>
|
|
38
|
+
: IsArray<T> extends true
|
|
39
|
+
? // determine allowed match values for array or tuple
|
|
45
40
|
| Match.Arr<T, C, P, R>
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
| Match.Entry<T[number & keyof T], C[number & keyof C], P, R>[]
|
|
42
|
+
| Match.Func<
|
|
43
|
+
T,
|
|
44
|
+
P,
|
|
45
|
+
R,
|
|
46
|
+
| Match.Arr<T, C, P, R>
|
|
47
|
+
| Match.Entry<
|
|
48
|
+
T[number & keyof T],
|
|
49
|
+
C[number & keyof C],
|
|
50
|
+
P,
|
|
51
|
+
R
|
|
52
|
+
>[]
|
|
53
|
+
>
|
|
54
|
+
: // only accept values with same interface
|
|
55
|
+
Match.WithResult<T, P, R, { [K in keyof C]: C[K & keyof T] }>;
|
|
50
56
|
|
|
51
57
|
/**
|
|
52
58
|
* The type that determines allowed matchers for objects.
|
|
@@ -128,7 +134,7 @@ export namespace Match {
|
|
|
128
134
|
export type ArrayTraversalType = `${CompoundType}Item`;
|
|
129
135
|
|
|
130
136
|
/**
|
|
131
|
-
*
|
|
137
|
+
* Compound matcher for objects, represented as an array starting with a compound type keyword.
|
|
132
138
|
* @typeparam T - the input value type
|
|
133
139
|
* @typeparam C - utility type
|
|
134
140
|
* @typeparam P - the parent type
|
|
@@ -136,7 +142,7 @@ export namespace Match {
|
|
|
136
142
|
*/
|
|
137
143
|
export type CompoundForObj<T, C, P, R> = [
|
|
138
144
|
Match.CompoundType,
|
|
139
|
-
...Match.Entry<T, C, P, R>[]
|
|
145
|
+
...Match.Entry<T, C, P, R>[],
|
|
140
146
|
];
|
|
141
147
|
|
|
142
148
|
/**
|
|
@@ -188,7 +194,7 @@ export namespace Match {
|
|
|
188
194
|
* match(input, { a: 2 }) // => false
|
|
189
195
|
* match(input, { a: (v) => v > 10 }) // => false
|
|
190
196
|
* match(input, { b: { c: true }}) // => true
|
|
191
|
-
* match(input,
|
|
197
|
+
* match(input, ['every', { a: (v) => v > 0 }, { b: { c: true } }]) // => true
|
|
192
198
|
* match(input, { b: { c: (v, parent, root) => v && parent.d.length > 0 && root.a > 0 } })
|
|
193
199
|
* // => true
|
|
194
200
|
* ```
|
|
@@ -272,9 +278,7 @@ function matchEntry<T, C, P, R>(
|
|
|
272
278
|
// already determined above that the source and matcher are not equal
|
|
273
279
|
|
|
274
280
|
failureLog?.push(
|
|
275
|
-
`value ${JSON.stringify(
|
|
276
|
-
source
|
|
277
|
-
)} does not match given matcher ${JSON.stringify(matcher)}`
|
|
281
|
+
`value ${JSON.stringify(source)} does not match given matcher ${JSON.stringify(matcher)}`
|
|
278
282
|
);
|
|
279
283
|
|
|
280
284
|
return false;
|
|
@@ -469,9 +473,7 @@ function matchPlainObj<T extends object, C, P, R>(
|
|
|
469
473
|
// the source does not have the given key
|
|
470
474
|
|
|
471
475
|
failureLog?.push(
|
|
472
|
-
`key ${key} is specified in matcher but not present in value ${JSON.stringify(
|
|
473
|
-
source
|
|
474
|
-
)}`
|
|
476
|
+
`key ${key} is specified in matcher but not present in value ${JSON.stringify(source)}`
|
|
475
477
|
);
|
|
476
478
|
|
|
477
479
|
return false;
|
package/dist/bun/patch.mts
CHANGED
|
@@ -22,15 +22,16 @@ export namespace Patch {
|
|
|
22
22
|
* @typeparam P - the parent type
|
|
23
23
|
* @typeparam R - the root object type
|
|
24
24
|
*/
|
|
25
|
-
export type Entry<T, C, P, R> =
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
25
|
+
export type Entry<T, C, P, R> =
|
|
26
|
+
IsAnyFunc<T> extends true
|
|
27
|
+
? T
|
|
28
|
+
: IsPlainObj<T> extends true
|
|
29
|
+
? Patch.WithResult<T, P, R, Patch.Obj<T, C, R>>
|
|
30
|
+
: Tuple.IsTuple<T> extends true
|
|
31
|
+
? Patch.WithResult<T, P, R, T | Patch.Tup<T, C, R>>
|
|
32
|
+
: IsArray<T> extends true
|
|
33
|
+
? Patch.WithResult<T, P, R, T>
|
|
34
|
+
: Patch.WithResult<T, P, R, T>;
|
|
34
35
|
|
|
35
36
|
/**
|
|
36
37
|
* Either result type S, or a patch function with the value type, the parent type, and the root type.
|
|
@@ -109,7 +110,7 @@ export namespace Patch {
|
|
|
109
110
|
* patch(input, [{ a: 2 }]) // => { a: 2, b: { c: true, d: 'a' } }
|
|
110
111
|
* patch(input, [{ b: [{ c: (v) => !v }] }] )
|
|
111
112
|
* // => { a: 1, b: { c: false, d: 'a' } }
|
|
112
|
-
* patch(input
|
|
113
|
+
* patch(input, [{ a: (v) => v + 1, b: [{ d: 'q' }] }] )
|
|
113
114
|
* // => { a: 2, b: { c: true, d: 'q' } }
|
|
114
115
|
* ```
|
|
115
116
|
*/
|