decoders 2.0.0-beta5 → 2.0.0-beta9
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/CHANGELOG.md +19 -0
- package/NotSupportedTSVersion.d.ts +1 -0
- package/README.md +934 -387
- package/_guard.d.ts +7 -0
- package/_guard.js +2 -6
- package/_guard.js.flow +3 -3
- package/{_esm/_guard.js → _guard.mjs} +3 -3
- package/_types.d.ts +13 -0
- package/{_esm/_types.js → _types.mjs} +0 -0
- package/_utils.d.ts +10 -0
- package/_utils.js +1 -1
- package/_utils.js.flow +3 -3
- package/{_esm/_utils.js → _utils.mjs} +1 -1
- package/annotate.d.ts +62 -0
- package/{_esm/annotate.js → annotate.mjs} +0 -0
- package/core/_helpers.d.ts +79 -0
- package/core/array.d.ts +8 -0
- package/core/array.js +19 -12
- package/core/array.js.flow +15 -11
- package/{_esm/core/array.js → core/array.mjs} +19 -10
- package/core/boolean.d.ts +5 -0
- package/core/boolean.js +5 -9
- package/core/boolean.js.flow +5 -7
- package/{_esm/core/boolean.js → core/boolean.mjs} +7 -7
- package/core/composition.d.ts +18 -0
- package/core/composition.js +41 -15
- package/core/composition.js.flow +41 -10
- package/core/composition.mjs +70 -0
- package/core/constants.d.ts +11 -0
- package/core/constants.js +6 -10
- package/core/constants.js.flow +7 -9
- package/{_esm/core/constants.js → core/constants.mjs} +7 -7
- package/core/date.d.ts +4 -0
- package/core/date.js +5 -9
- package/core/date.js.flow +4 -6
- package/{_esm/core/date.js → core/date.mjs} +7 -7
- package/core/describe.d.ts +3 -0
- package/core/describe.js +2 -6
- package/core/describe.js.flow +2 -2
- package/{_esm/core/describe.js → core/describe.mjs} +3 -3
- package/core/dispatch.d.ts +8 -0
- package/core/dispatch.js +11 -13
- package/core/dispatch.js.flow +13 -12
- package/{_esm/core/dispatch.js → core/dispatch.mjs} +12 -11
- package/core/either.d.ts +66 -0
- package/core/either.js +34 -50
- package/core/either.js.flow +40 -86
- package/core/either.mjs +90 -0
- package/core/fail.d.ts +3 -0
- package/core/fail.js +2 -6
- package/core/fail.js.flow +2 -2
- package/{_esm/core/fail.js → core/fail.mjs} +3 -3
- package/core/instanceOf.d.ts +3 -0
- package/core/instanceOf.js +2 -6
- package/core/instanceOf.js.flow +3 -3
- package/core/instanceOf.mjs +8 -0
- package/core/json.d.ts +11 -0
- package/core/json.js +3 -3
- package/core/json.js.flow +3 -3
- package/core/json.mjs +15 -0
- package/core/lazy.d.ts +3 -0
- package/{_esm/core/lazy.js → core/lazy.mjs} +0 -0
- package/core/number.d.ts +6 -0
- package/core/number.js +9 -13
- package/core/number.js.flow +18 -12
- package/core/number.mjs +25 -0
- package/core/object.d.ts +38 -0
- package/core/object.js +66 -13
- package/core/object.js.flow +84 -28
- package/{_esm/core/object.js → core/object.mjs} +64 -11
- package/core/optional.d.ts +5 -0
- package/core/optional.js +4 -8
- package/core/optional.js.flow +3 -3
- package/{_esm/core/optional.js → core/optional.mjs} +6 -6
- package/core/string.d.ts +13 -0
- package/core/string.js +31 -49
- package/core/string.js.flow +29 -39
- package/core/string.mjs +58 -0
- package/core/tuple.d.ts +30 -0
- package/core/tuple.js +30 -149
- package/core/tuple.js.flow +33 -197
- package/core/tuple.mjs +45 -0
- package/format.d.ts +4 -0
- package/{format/inline.js → format.js} +6 -1
- package/{_esm/format/inline.js.flow → format.js.flow} +6 -2
- package/{_esm/format/inline.js → format.mjs} +4 -1
- package/index.d.ts +42 -0
- package/index.js +33 -42
- package/index.js.flow +17 -18
- package/{_esm/index.js → index.mjs} +18 -19
- package/package.json +15 -3
- package/result.d.ts +39 -0
- package/result.js +9 -90
- package/result.js.flow +11 -87
- package/result.mjs +81 -0
- package/_esm/_guard.js.flow +0 -20
- package/_esm/_types.js.flow +0 -20
- package/_esm/_utils.js.flow +0 -97
- package/_esm/annotate.js.flow +0 -218
- package/_esm/core/array.js.flow +0 -103
- package/_esm/core/boolean.js.flow +0 -29
- package/_esm/core/composition.js +0 -42
- package/_esm/core/composition.js.flow +0 -43
- package/_esm/core/constants.js.flow +0 -46
- package/_esm/core/date.js.flow +0 -40
- package/_esm/core/describe.js.flow +0 -17
- package/_esm/core/dispatch.js.flow +0 -58
- package/_esm/core/either.js +0 -90
- package/_esm/core/either.js.flow +0 -151
- package/_esm/core/fail.js.flow +0 -12
- package/_esm/core/instanceOf.js +0 -8
- package/_esm/core/instanceOf.js.flow +0 -20
- package/_esm/core/json.js +0 -15
- package/_esm/core/json.js.flow +0 -28
- package/_esm/core/lazy.js.flow +0 -15
- package/_esm/core/mapping.js +0 -54
- package/_esm/core/mapping.js.flow +0 -54
- package/_esm/core/number.js +0 -25
- package/_esm/core/number.js.flow +0 -34
- package/_esm/core/object.js.flow +0 -203
- package/_esm/core/optional.js.flow +0 -41
- package/_esm/core/string.js +0 -76
- package/_esm/core/string.js.flow +0 -82
- package/_esm/core/tuple.js +0 -155
- package/_esm/core/tuple.js.flow +0 -215
- package/_esm/format/index.js +0 -2
- package/_esm/format/index.js.flow +0 -4
- package/_esm/format/short.js +0 -4
- package/_esm/format/short.js.flow +0 -8
- package/_esm/index.js.flow +0 -63
- package/_esm/result.js +0 -148
- package/_esm/result.js.flow +0 -174
- package/core/mapping.js +0 -67
- package/core/mapping.js.flow +0 -54
- package/format/index.js +0 -12
- package/format/index.js.flow +0 -4
- package/format/inline.js.flow +0 -122
- package/format/short.js +0 -10
- package/format/short.js.flow +0 -8
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/decoders)
|
|
4
4
|
[](https://github.com/nvie/decoders/actions)
|
|
5
|
-
[](https://coveralls.io/github/nvie/decoders?branch=main)
|
|
6
6
|
[](https://bundlephobia.com/result?p=decoders)
|
|
7
7
|
|
|
8
8
|
Elegant and battle-tested validation library for type-safe input data for TypeScript and
|
|
@@ -68,231 +68,567 @@ And then, you can use it to decode values:
|
|
|
68
68
|
... })
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
+
## Understanding decoders and guards
|
|
72
|
+
|
|
73
|
+
At the heart, a decoder is a function that will take _any_ unsafe input, verify it, and
|
|
74
|
+
either return an "ok" or an annotated "err" result. It will never throw an error when
|
|
75
|
+
called.
|
|
76
|
+
|
|
77
|
+
A guard is a convenience wrapper which will use the decoder
|
|
78
|
+
|
|
71
79
|
## API
|
|
72
80
|
|
|
73
81
|
The decoders package consists of a few building blocks:
|
|
74
82
|
|
|
83
|
+
- [Guards](#guards)
|
|
75
84
|
- [Primitives](#primitives)
|
|
76
85
|
- [Compositions](#compositions)
|
|
77
86
|
- [Building custom decoders](#building-custom-decoders)
|
|
78
87
|
|
|
88
|
+
### Guards
|
|
89
|
+
|
|
90
|
+
<a name="guard" href="#guard">#</a> <b>guard</b>(decoder: <i>Decoder<T></i>,
|
|
91
|
+
formatter?: <i>Annotation => string</i>): <i>Guard<T></i>
|
|
92
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/_guard.js 'Source')
|
|
93
|
+
|
|
94
|
+
Turns any given `Decoder<T>` into a `Guard<T>`.
|
|
95
|
+
|
|
96
|
+
A guard works like a decoder, but will either:
|
|
97
|
+
|
|
98
|
+
- Return the decoded value (aka the happy path)
|
|
99
|
+
- Or throw an exception
|
|
100
|
+
|
|
101
|
+
So a Guard bypasses the intermediate "Result" type that decoders output. An "ok" result
|
|
102
|
+
will get returned, an "err" result will be formatted into an error message and thrown.
|
|
103
|
+
|
|
104
|
+
The typical usage is that you keep composing decoders until you have one decoder for your
|
|
105
|
+
entire input object, and then use a guard to wrap that outer decoder. Decoders can be
|
|
106
|
+
composed to build larger decoders. Guards cannot be composed.
|
|
107
|
+
|
|
108
|
+
#### Formatting error messsages
|
|
109
|
+
|
|
110
|
+
By default, `guard()` will use the `formatInline` error formatter. You can pass another
|
|
111
|
+
built-in formatter as the second argument, or provide your own. (This will require
|
|
112
|
+
understanding the internal `Annotation` datastructure that decoders uses for error
|
|
113
|
+
reporting.)
|
|
114
|
+
|
|
115
|
+
Built-in formatters are:
|
|
116
|
+
|
|
117
|
+
- `formatInline` (default) — will echo back the input object and inline error messages
|
|
118
|
+
smartly. Example:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { array, guard, object, string } from 'decoders';
|
|
122
|
+
import { formatInline } from 'decoders/format';
|
|
123
|
+
|
|
124
|
+
const mydecoder = array(object({ name: string, age: number }));
|
|
125
|
+
|
|
126
|
+
const defaultGuard = guard(mydecoder, formatInline);
|
|
127
|
+
defaultGuard([{ name: 'Alice', age: '33' }]);
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Will throw the following error message:
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
Decoding error:
|
|
134
|
+
[
|
|
135
|
+
{
|
|
136
|
+
name: 'Alice',
|
|
137
|
+
age: '33',
|
|
138
|
+
^^^^ Must be number
|
|
139
|
+
},
|
|
140
|
+
]
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
- `formatShort` — will report the _path_ into the object where the error happened.
|
|
144
|
+
Example:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import { formatShort } from 'decoders/format';
|
|
148
|
+
const customGuard = guard(mydecoder, formatShort);
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Will throw the following error message:
|
|
152
|
+
|
|
153
|
+
```text
|
|
154
|
+
Decoding error: Value at keypath 0.age: Must be number
|
|
155
|
+
```
|
|
156
|
+
|
|
79
157
|
### Primitives
|
|
80
158
|
|
|
81
159
|
<a name="number" href="#number">#</a> <b>number</b>: <i>Decoder<number></i>
|
|
82
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
160
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/number.js 'Source')
|
|
83
161
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
numbers.
|
|
162
|
+
Accepts only finite numbers (integer or float values). This means that values like `NaN`,
|
|
163
|
+
or positive and negative `Infinity` are not considered valid numbers.
|
|
87
164
|
|
|
165
|
+
<!-- prettier-ignore-start -->
|
|
88
166
|
```javascript
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
167
|
+
const verify = guard(number);
|
|
168
|
+
|
|
169
|
+
// 👍
|
|
170
|
+
verify(123) === 123;
|
|
171
|
+
verify(-3.14) === -3.14;
|
|
172
|
+
|
|
173
|
+
// 👎
|
|
174
|
+
verify(Infinity); // throws
|
|
175
|
+
verify(NaN); // throws
|
|
176
|
+
verify('not a number'); // throws
|
|
94
177
|
```
|
|
178
|
+
<!-- prettier-ignore-end -->
|
|
95
179
|
|
|
96
180
|
---
|
|
97
181
|
|
|
98
182
|
<a name="integer" href="#integer">#</a> <b>integer</b>: <i>Decoder<integer></i>
|
|
99
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
183
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/number.js 'Source')
|
|
100
184
|
|
|
101
|
-
Like `number`, but only
|
|
185
|
+
Like `number`, but only accepts values that are whole numbers.
|
|
102
186
|
|
|
187
|
+
<!-- prettier-ignore-start -->
|
|
103
188
|
```javascript
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
189
|
+
const verify = guard(integer);
|
|
190
|
+
|
|
191
|
+
// 👍
|
|
192
|
+
verify(123) === 123;
|
|
193
|
+
|
|
194
|
+
// 👎
|
|
195
|
+
verify(-3.14); // throws
|
|
196
|
+
verify(Infinity); // throws
|
|
197
|
+
verify(NaN); // throws
|
|
198
|
+
verify('not a integer'); // throws
|
|
109
199
|
```
|
|
200
|
+
<!-- prettier-ignore-end -->
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
<a name="positiveNumber" href="#positiveNumber">#</a> <b>positiveNumber</b>:
|
|
205
|
+
<i>Decoder<number></i>
|
|
206
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/number.js 'Source')
|
|
207
|
+
|
|
208
|
+
Accepts only positive finite numbers (integer or float values).
|
|
209
|
+
|
|
210
|
+
<!-- prettier-ignore-start -->
|
|
211
|
+
```javascript
|
|
212
|
+
const verify = guard(positiveNumber);
|
|
213
|
+
|
|
214
|
+
// 👍
|
|
215
|
+
verify(123) === 123;
|
|
216
|
+
|
|
217
|
+
// 👎
|
|
218
|
+
verify(-42); // throws
|
|
219
|
+
verify(3.14); // throws
|
|
220
|
+
verify(Infinity); // throws
|
|
221
|
+
verify(NaN); // throws
|
|
222
|
+
verify('not a number'); // throws
|
|
223
|
+
```
|
|
224
|
+
<!-- prettier-ignore-end -->
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
<a name="positiveInteger" href="#positiveInteger">#</a> <b>positiveInteger</b>:
|
|
229
|
+
<i>Decoder<number></i>
|
|
230
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/number.js 'Source')
|
|
231
|
+
|
|
232
|
+
Accepts only positive finite integers.
|
|
233
|
+
|
|
234
|
+
<!-- prettier-ignore-start -->
|
|
235
|
+
```javascript
|
|
236
|
+
const verify = guard(positiveInteger);
|
|
237
|
+
|
|
238
|
+
// 👍
|
|
239
|
+
verify(123) === 123;
|
|
240
|
+
|
|
241
|
+
// 👎
|
|
242
|
+
verify(-3); // throws
|
|
243
|
+
verify(3.14); // throws
|
|
244
|
+
verify(Infinity); // throws
|
|
245
|
+
verify(NaN); // throws
|
|
246
|
+
verify('not a number'); // throws
|
|
247
|
+
```
|
|
248
|
+
<!-- prettier-ignore-end -->
|
|
110
249
|
|
|
111
250
|
---
|
|
112
251
|
|
|
113
252
|
<a name="string" href="#string">#</a> <b>string</b>: <i>Decoder<string></i>
|
|
114
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
253
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/string.js 'Source')
|
|
115
254
|
|
|
116
|
-
|
|
255
|
+
Accepts only string values.
|
|
117
256
|
|
|
257
|
+
<!-- prettier-ignore-start -->
|
|
118
258
|
```javascript
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
259
|
+
const verify = guard(string);
|
|
260
|
+
|
|
261
|
+
// 👍
|
|
262
|
+
verify('hello world') === 'hello world';
|
|
263
|
+
verify('🚀') === '🚀';
|
|
264
|
+
verify('') === '';
|
|
265
|
+
|
|
266
|
+
// 👎
|
|
267
|
+
verify(123); // throws
|
|
268
|
+
verify(true); // throws
|
|
269
|
+
verify(null); // throws
|
|
122
270
|
```
|
|
271
|
+
<!-- prettier-ignore-end -->
|
|
123
272
|
|
|
124
273
|
---
|
|
125
274
|
|
|
126
275
|
<a name="nonEmptyString" href="#nonEmptyString">#</a> <b>nonEmptyString</b>:
|
|
127
276
|
<i>Decoder<string></i>
|
|
128
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
277
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/string.js 'Source')
|
|
129
278
|
|
|
130
|
-
Like `string`, but will
|
|
279
|
+
Like `string`, but will reject the empty string, or strings containing only whitespace.
|
|
131
280
|
|
|
281
|
+
<!-- prettier-ignore-start -->
|
|
132
282
|
```javascript
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
283
|
+
const verify = guard(nonEmptyString);
|
|
284
|
+
|
|
285
|
+
// 👍
|
|
286
|
+
verify('hello world') === 'hello world';
|
|
287
|
+
verify('🚀') === '🚀';
|
|
288
|
+
|
|
289
|
+
// 👎
|
|
290
|
+
verify(123); // throws
|
|
291
|
+
verify(' '); // throws
|
|
292
|
+
verify(''); // throws
|
|
138
293
|
```
|
|
294
|
+
<!-- prettier-ignore-end -->
|
|
139
295
|
|
|
140
296
|
---
|
|
141
297
|
|
|
142
298
|
<a name="regex" href="#regex">#</a> <b>regex</b>(): <i>Decoder<string></i>
|
|
143
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
299
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/string.js 'Source')
|
|
144
300
|
|
|
145
|
-
|
|
146
|
-
expression.
|
|
301
|
+
Accepts only string values that match the given regular expression.
|
|
147
302
|
|
|
303
|
+
<!-- prettier-ignore-start -->
|
|
148
304
|
```javascript
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
305
|
+
const verify = guard(regex(/^[0-9][0-9]+$/));
|
|
306
|
+
|
|
307
|
+
// 👍
|
|
308
|
+
verify('42') === '42';
|
|
309
|
+
verify('83401648364738') === '83401648364738';
|
|
310
|
+
|
|
311
|
+
// 👎
|
|
312
|
+
verify(''); // throws
|
|
313
|
+
verify('1'); // throws
|
|
314
|
+
verify('foo'); // throws
|
|
152
315
|
```
|
|
316
|
+
<!-- prettier-ignore-end -->
|
|
153
317
|
|
|
154
318
|
---
|
|
155
319
|
|
|
156
320
|
<a name="email" href="#email">#</a> <b>email</b>: <i>Decoder<string></i>
|
|
157
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
321
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/string.js 'Source')
|
|
158
322
|
|
|
159
|
-
|
|
323
|
+
Accepts only strings that are syntactically valid email addresses. (This will not mean
|
|
324
|
+
that the email address actually exist.)
|
|
160
325
|
|
|
326
|
+
<!-- prettier-ignore-start -->
|
|
161
327
|
```javascript
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
328
|
+
const verify = guard(email);
|
|
329
|
+
|
|
330
|
+
// 👍
|
|
331
|
+
verify('alice@acme.org') === 'alice@acme.org';
|
|
332
|
+
|
|
333
|
+
// 👎
|
|
334
|
+
verify('foo'); // throws
|
|
335
|
+
verify('@acme.org'); // throws
|
|
336
|
+
verify('alice @ acme.org'); // throws
|
|
165
337
|
```
|
|
338
|
+
<!-- prettier-ignore-end -->
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
<a name="url" href="#url">#</a> <b>url</b>: <i>Decoder<URL></i>
|
|
343
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/string.js 'Source')
|
|
344
|
+
|
|
345
|
+
Accepts strings that are valid URLs, returns the value as a URL instance.
|
|
346
|
+
|
|
347
|
+
<!-- prettier-ignore-start -->
|
|
348
|
+
```javascript
|
|
349
|
+
const verify = guard(url);
|
|
350
|
+
|
|
351
|
+
// 👍
|
|
352
|
+
verify('http://nvie.com') === new URL('http://nvie.com/');
|
|
353
|
+
verify('https://nvie.com') === new URL('https://nvie.com/');
|
|
354
|
+
verify('git+ssh://user@github.com/foo/bar.git') === new URL('git+ssh://user@github.com/foo/bar.git');
|
|
355
|
+
|
|
356
|
+
// 👎
|
|
357
|
+
verify('foo'); // throws
|
|
358
|
+
verify('@acme.org'); // throws
|
|
359
|
+
verify('alice @ acme.org'); // throws
|
|
360
|
+
verify('/search?q=foo'); // throws
|
|
361
|
+
```
|
|
362
|
+
<!-- prettier-ignore-end -->
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
<a name="httpsUrl" href="#httpsUrl">#</a> <b>httpsUrl</b>: <i>Decoder<URL></i>
|
|
367
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/string.js 'Source')
|
|
368
|
+
|
|
369
|
+
Accepts strings that are valid URLs, but only HTTPS ones. Returns the value as a URL
|
|
370
|
+
instance.
|
|
371
|
+
|
|
372
|
+
<!-- prettier-ignore-start -->
|
|
373
|
+
```javascript
|
|
374
|
+
const verify = guard(httpsUrl);
|
|
375
|
+
|
|
376
|
+
// 👍
|
|
377
|
+
verify('https://nvie.com:443') === new URL('https://nvie.com/');
|
|
378
|
+
|
|
379
|
+
// 👎
|
|
380
|
+
verify('http://nvie.com'); // throws, not HTTPS
|
|
381
|
+
verify('git+ssh://user@github.com/foo/bar.git'); // throws, not HTTPS
|
|
382
|
+
```
|
|
383
|
+
<!-- prettier-ignore-end -->
|
|
384
|
+
|
|
385
|
+
**Tip!** If you need to limit URLs to different protocols than HTTP, you can do as the
|
|
386
|
+
HTTPS decoder is implemented: as a predicate on top of a regular `url` decoder.
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
import { predicate, url } from 'decoders';
|
|
390
|
+
|
|
391
|
+
const gitUrl: Decoder<URL> = predicate(
|
|
392
|
+
url,
|
|
393
|
+
(value) => value.protocol === 'git:',
|
|
394
|
+
'Must be a git:// URL',
|
|
395
|
+
);
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
<a name="uuid" href="#uuid">#</a> <b>uuid</b>: <i>Decoder<string></i>
|
|
401
|
+
[(source)](https://github.com/nvie/decoders/blob/main/src/core/string.js 'Source')
|
|
402
|
+
|
|
403
|
+
Accepts strings that are valid [UUIDs][wiki-uuid] (universally unique identifier).
|
|
404
|
+
|
|
405
|
+
<!-- prettier-ignore-start -->
|
|
406
|
+
```javascript
|
|
407
|
+
const verify = guard(uuid);
|
|
408
|
+
|
|
409
|
+
// 👍
|
|
410
|
+
verify('123e4567-e89b-12d3-a456-426614174000') === '123e4567-e89b-12d3-a456-426614174000'
|
|
411
|
+
verify('123E4567-E89B-12D3-A456-426614174000') === '123E4567-E89B-12D3-A456-426614174000'
|
|
412
|
+
|
|
413
|
+
// 👎
|
|
414
|
+
verify('123E4567E89B12D3A456426614174000'); // throws
|
|
415
|
+
verify('abcdefgh-ijkl-mnop-qrst-uvwxyz012345'); // throws
|
|
416
|
+
```
|
|
417
|
+
<!-- prettier-ignore-end -->
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
<a name="uuidv1" href="#uuidv1">#</a> <b>uuidv1</b>: <i>Decoder<string></i>
|
|
422
|
+
[(source)](https://github.com/nvie/decoders/blob/main/src/core/string.js 'Source')
|
|
423
|
+
|
|
424
|
+
Like `uuid`, but only accepts [UUIDv1s][wiki-uuidv1] strings.
|
|
425
|
+
|
|
426
|
+
<!-- prettier-ignore-start -->
|
|
427
|
+
```javascript
|
|
428
|
+
const verify = guard(uuidv1);
|
|
429
|
+
|
|
430
|
+
// 👍
|
|
431
|
+
verify('123e4567-e89b-12d3-a456-426614174000') === '123e4567-e89b-42d3-a456-426614174000'
|
|
432
|
+
|
|
433
|
+
// 👎
|
|
434
|
+
verify('123e4567-e89b-42d3-a456-426614174000') // throws
|
|
435
|
+
```
|
|
436
|
+
<!-- prettier-ignore-end -->
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
<a name="uuidv4" href="#uuidv4">#</a> <b>uuidv4</b>: <i>Decoder<string></i>
|
|
441
|
+
[(source)](https://github.com/nvie/decoders/blob/main/src/core/string.js 'Source')
|
|
442
|
+
|
|
443
|
+
Like `uuid`, but only accepts [UUIDv4s][wiki-uuidv4] strings.
|
|
444
|
+
|
|
445
|
+
<!-- prettier-ignore-start -->
|
|
446
|
+
```javascript
|
|
447
|
+
const verify = guard(uuidv4);
|
|
448
|
+
|
|
449
|
+
// 👍
|
|
450
|
+
verify('123e4567-e89b-42d3-a456-426614174000') === '123e4567-e89b-42d3-a456-426614174000'
|
|
451
|
+
|
|
452
|
+
// 👎
|
|
453
|
+
verify('123e4567-e89b-12d3-a456-426614174000') // throws
|
|
454
|
+
```
|
|
455
|
+
<!-- prettier-ignore-end -->
|
|
166
456
|
|
|
167
457
|
---
|
|
168
458
|
|
|
169
459
|
<a name="boolean" href="#boolean">#</a> <b>boolean</b>: <i>Decoder<boolean></i>
|
|
170
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
460
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/boolean.js 'Source')
|
|
171
461
|
|
|
172
|
-
|
|
462
|
+
Accepts only boolean values.
|
|
173
463
|
|
|
464
|
+
<!-- prettier-ignore-start -->
|
|
174
465
|
```javascript
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
466
|
+
const verify = guard(boolean);
|
|
467
|
+
|
|
468
|
+
// 👍
|
|
469
|
+
verify(false) === false;
|
|
470
|
+
verify(true) === true;
|
|
471
|
+
|
|
472
|
+
// 👎
|
|
473
|
+
verify(undefined); // throws
|
|
474
|
+
verify('hello world'); // throws
|
|
475
|
+
verify(123); // throws
|
|
181
476
|
```
|
|
477
|
+
<!-- prettier-ignore-end -->
|
|
182
478
|
|
|
183
479
|
---
|
|
184
480
|
|
|
185
481
|
<a name="truthy" href="#truthy">#</a> <b>truthy</b>: <i>Decoder<boolean></i>
|
|
186
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
482
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/boolean.js 'Source')
|
|
187
483
|
|
|
188
|
-
|
|
484
|
+
Accepts any value and will return its "truth" value. Will never reject.
|
|
189
485
|
|
|
190
486
|
```javascript
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
487
|
+
const verify = guard(truthy);
|
|
488
|
+
|
|
489
|
+
// 👍
|
|
490
|
+
verify(false) === false;
|
|
491
|
+
verify(true) === true;
|
|
492
|
+
verify(undefined) === false;
|
|
493
|
+
verify('hello world') === true;
|
|
494
|
+
verify('false') === true;
|
|
495
|
+
verify(0) === false;
|
|
496
|
+
verify(1) === true;
|
|
497
|
+
verify(null) === false;
|
|
498
|
+
|
|
499
|
+
// 👎
|
|
500
|
+
// This decoder will never reject an input
|
|
200
501
|
```
|
|
201
502
|
|
|
202
503
|
---
|
|
203
504
|
|
|
204
505
|
<a name="numericBoolean" href="#numericBoolean">#</a> <b>numericBoolean</b>:
|
|
205
506
|
<i>Decoder<boolean></i>
|
|
206
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
507
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/boolean.js 'Source')
|
|
207
508
|
|
|
208
|
-
|
|
509
|
+
Accepts only number values, but return their boolean representation.
|
|
209
510
|
|
|
511
|
+
<!-- prettier-ignore-start -->
|
|
210
512
|
```javascript
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
513
|
+
const verify = guard(numericBoolean);
|
|
514
|
+
|
|
515
|
+
// 👍
|
|
516
|
+
verify(-1) === true;
|
|
517
|
+
verify(0) === false;
|
|
518
|
+
verify(123) === true;
|
|
519
|
+
|
|
520
|
+
// 👎
|
|
521
|
+
verify(false); // throws
|
|
522
|
+
verify(true); // throws
|
|
523
|
+
verify(undefined); // throws
|
|
524
|
+
verify('hello'); // throws
|
|
219
525
|
```
|
|
526
|
+
<!-- prettier-ignore-end -->
|
|
220
527
|
|
|
221
528
|
---
|
|
222
529
|
|
|
223
530
|
<a name="date" href="#date">#</a> <b>date</b>: <i>Decoder<Date></i>
|
|
224
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
531
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/date.js 'Source')
|
|
225
532
|
|
|
226
|
-
|
|
227
|
-
[Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date)
|
|
228
|
-
values.
|
|
533
|
+
Accepts only JavaScript [Date][date-api] values.
|
|
229
534
|
|
|
535
|
+
<!-- prettier-ignore-start -->
|
|
230
536
|
```javascript
|
|
537
|
+
const verify = guard(date);
|
|
231
538
|
const now = new Date();
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
539
|
+
|
|
540
|
+
// 👍
|
|
541
|
+
verify(now) === now;
|
|
542
|
+
|
|
543
|
+
// 👎
|
|
544
|
+
verify(123); // throws
|
|
545
|
+
verify('hello'); // throws
|
|
236
546
|
```
|
|
547
|
+
<!-- prettier-ignore-end -->
|
|
237
548
|
|
|
238
549
|
---
|
|
239
550
|
|
|
240
551
|
<a name="iso8601" href="#iso8601">#</a> <b>iso8601</b>: <i>Decoder<Date></i>
|
|
241
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
552
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/date.js 'Source')
|
|
242
553
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
decode them as `iso8601` when receiving.
|
|
554
|
+
Accepts only [ISO8601][iso8601-fmt]-formatted strings. This is very useful for working
|
|
555
|
+
with dates in APIs: serialize them as `.toISOString()` when sending, decode them with
|
|
556
|
+
`iso8601` when receiving.
|
|
247
557
|
|
|
248
|
-
**NOTE:** This decoder
|
|
558
|
+
**NOTE:** This decoder accepts _strings_, but returns _Date_ instances.
|
|
249
559
|
|
|
560
|
+
<!-- prettier-ignore-start -->
|
|
250
561
|
```javascript
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
562
|
+
const verify = guard(iso8601);
|
|
563
|
+
|
|
564
|
+
// 👍
|
|
565
|
+
verify('2020-06-01T12:00:00Z'); // ≈ new Date('2020-06-01T12:00:00Z')
|
|
566
|
+
|
|
567
|
+
// 👎
|
|
568
|
+
verify('2020-06-01'); // throws
|
|
569
|
+
verify('hello'); // throws
|
|
570
|
+
verify(123); // throws
|
|
571
|
+
verify(new Date()); // throws (does not accept dates)
|
|
256
572
|
```
|
|
573
|
+
<!-- prettier-ignore-end -->
|
|
257
574
|
|
|
258
575
|
---
|
|
259
576
|
|
|
260
577
|
<a name="null_" href="#null_">#</a> <b>null\_</b>: <i>Decoder<null></i>
|
|
261
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
578
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/constants.js 'Source')
|
|
262
579
|
|
|
263
|
-
|
|
580
|
+
Accepts only the literal `null` value.
|
|
264
581
|
|
|
582
|
+
<!-- prettier-ignore-start -->
|
|
265
583
|
```javascript
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
584
|
+
const verify = guard(null_);
|
|
585
|
+
|
|
586
|
+
// 👍
|
|
587
|
+
verify(null) === null;
|
|
588
|
+
|
|
589
|
+
// 👎
|
|
590
|
+
verify(false); // throws
|
|
591
|
+
verify(undefined); // throws
|
|
592
|
+
verify('hello world'); // throws
|
|
271
593
|
```
|
|
594
|
+
<!-- prettier-ignore-end -->
|
|
272
595
|
|
|
273
596
|
---
|
|
274
597
|
|
|
275
598
|
<a name="undefined_" href="#undefined_">#</a> <b>undefined\_</b>:
|
|
276
|
-
<i>Decoder<
|
|
277
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
599
|
+
<i>Decoder<undefined></i>
|
|
600
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/constants.js 'Source')
|
|
278
601
|
|
|
279
|
-
|
|
602
|
+
Accepts only the literal `undefined` value.
|
|
280
603
|
|
|
604
|
+
<!-- prettier-ignore-start -->
|
|
281
605
|
```javascript
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
606
|
+
const verify = guard(undefined_);
|
|
607
|
+
|
|
608
|
+
// 👍
|
|
609
|
+
verify(undefined) === undefined;
|
|
610
|
+
|
|
611
|
+
// 👎
|
|
612
|
+
verify(null); // throws
|
|
613
|
+
verify(false); // throws
|
|
614
|
+
verify('hello world'); // throws
|
|
287
615
|
```
|
|
616
|
+
<!-- prettier-ignore-end -->
|
|
288
617
|
|
|
289
618
|
---
|
|
290
619
|
|
|
291
620
|
<a name="constant" href="#constant">#</a> <b>constant</b><i><T></i>(value: T):
|
|
292
621
|
<i>Decoder<T></i>
|
|
293
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
622
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/constants.js 'Source')
|
|
623
|
+
|
|
624
|
+
Accepts only the given constant value.
|
|
294
625
|
|
|
295
|
-
|
|
626
|
+
For TypeScript, use this syntax:
|
|
627
|
+
|
|
628
|
+
```typescript
|
|
629
|
+
constant('something' as const);
|
|
630
|
+
constant(42 as const);
|
|
631
|
+
```
|
|
296
632
|
|
|
297
633
|
For Flow, use this syntax:
|
|
298
634
|
|
|
@@ -303,88 +639,119 @@ constant((42: 42));
|
|
|
303
639
|
|
|
304
640
|
Example:
|
|
305
641
|
|
|
642
|
+
<!-- prettier-ignore-start -->
|
|
306
643
|
```typescript
|
|
307
|
-
const
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
644
|
+
const verify = guard(constant('hello' as const));
|
|
645
|
+
|
|
646
|
+
// 👍
|
|
647
|
+
verify('hello') === 'hello';
|
|
648
|
+
|
|
649
|
+
// 👎
|
|
650
|
+
verify('this breaks'); // throws
|
|
651
|
+
verify(false); // throws
|
|
652
|
+
verify(undefined); // throws
|
|
312
653
|
```
|
|
654
|
+
<!-- prettier-ignore-end -->
|
|
313
655
|
|
|
314
656
|
---
|
|
315
657
|
|
|
316
658
|
<a name="hardcoded" href="#hardcoded">#</a> <b>hardcoded</b><i><T></i>(value: T):
|
|
317
659
|
<i>Decoder<T></i>
|
|
318
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
660
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/constants.js 'Source')
|
|
319
661
|
|
|
320
|
-
|
|
321
|
-
|
|
662
|
+
Accepts any input, completely ignores it, and always returns the provided value. This is
|
|
663
|
+
useful to manually add extra fields to object decoders.
|
|
322
664
|
|
|
665
|
+
<!-- prettier-ignore-start -->
|
|
323
666
|
```javascript
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
667
|
+
const verify = guard(hardcoded(42));
|
|
668
|
+
|
|
669
|
+
// 👍
|
|
670
|
+
verify('hello') === 42;
|
|
671
|
+
verify(false) === 42;
|
|
672
|
+
verify(undefined) === 42;
|
|
673
|
+
|
|
674
|
+
// 👎
|
|
675
|
+
// This decoder will never reject an input
|
|
328
676
|
```
|
|
677
|
+
<!-- prettier-ignore-end -->
|
|
329
678
|
|
|
330
679
|
---
|
|
331
680
|
|
|
332
681
|
<a name="fail" href="#fail">#</a> <b>fail</b>(): <i>Decoder<empty></i>
|
|
333
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
682
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/fail.js 'Source')
|
|
334
683
|
|
|
335
|
-
|
|
336
|
-
|
|
684
|
+
Rejects all inputs, and always fails with the given error message. May be useful for
|
|
685
|
+
explicitly disallowing keys, or for testing purposes.
|
|
337
686
|
|
|
687
|
+
<!-- prettier-ignore-start -->
|
|
338
688
|
```javascript
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
689
|
+
const verify = guard(object({
|
|
690
|
+
a: string,
|
|
691
|
+
b: optional(fail('Key b has been removed')),
|
|
692
|
+
}));
|
|
693
|
+
|
|
694
|
+
// 👍
|
|
695
|
+
verify({ a: 'foo' }); // ≈ { a: 'foo' };
|
|
696
|
+
verify({ a: 'foo', c: 'bar' }); // ≈ { a: 'foo' };
|
|
697
|
+
|
|
698
|
+
// 👎
|
|
699
|
+
verify({ a: 'foo', b: 'bar' }); // throws
|
|
343
700
|
```
|
|
701
|
+
<!-- prettier-ignore-end -->
|
|
344
702
|
|
|
345
703
|
---
|
|
346
704
|
|
|
347
|
-
<a name="mixed" href="#mixed">#</a> <b>mixed</b>: <i>Decoder<mixed></i>
|
|
348
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/constants.js 'Source')<br />
|
|
349
705
|
<a name="unknown" href="#unknown">#</a> <b>unknown</b>: <i>Decoder<unknown></i>
|
|
350
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
effectively returns a `Decoder<mixed>`, which is not that useful. **Use sparingly.**
|
|
706
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/constants.js 'Source')
|
|
707
|
+
<a name="mixed" href="#mixed">#</a> <b>mixed</b>: <i>Decoder<mixed></i>
|
|
708
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/constants.js 'Source')<br />
|
|
354
709
|
|
|
355
|
-
|
|
710
|
+
Accepts any value and returns it unchanged. Useful for situation in which you don't know
|
|
711
|
+
or expect a specific type. Of course, the downside is that you won't know the type of the
|
|
712
|
+
value statically and you'll have to further refine it yourself.
|
|
356
713
|
|
|
357
714
|
```javascript
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
715
|
+
const verify = guard(mixed);
|
|
716
|
+
|
|
717
|
+
// 👍
|
|
718
|
+
verify('hello') === 'hello';
|
|
719
|
+
verify(false) === false;
|
|
720
|
+
verify(undefined) === undefined;
|
|
721
|
+
verify([1, 2]) === [1, 2];
|
|
722
|
+
|
|
723
|
+
// 👎
|
|
724
|
+
// This decoder will never reject an input
|
|
363
725
|
```
|
|
364
726
|
|
|
365
727
|
### Compositions
|
|
366
728
|
|
|
367
|
-
Composite decoders
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
`Decoder<Array<Point>>`.
|
|
729
|
+
Composite decoders can build new decoders from existing decoders that can already decode a
|
|
730
|
+
"subtype". Examples are: if you already have a `string` decoder (of type
|
|
731
|
+
`Decoder<string>`), then you can use `array(string)` to automatically build a decoder for
|
|
732
|
+
arrays of strings, which will be of type `Decoder<Array<string>>`.
|
|
372
733
|
|
|
373
734
|
<a name="optional" href="#optional">#</a>
|
|
374
|
-
<b>optional</b><i><T></i>(<i>Decoder<T></i>): <i>Decoder<T |
|
|
375
|
-
|
|
735
|
+
<b>optional</b><i><T></i>(<i>Decoder<T></i>): <i>Decoder<T |
|
|
736
|
+
undefined></i>
|
|
737
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/optional.js 'Source')
|
|
376
738
|
|
|
377
|
-
|
|
378
|
-
provided that you already have a decoder for <i>T</i>.
|
|
739
|
+
Accepts only the literal value `undefined`, or whatever the given decoder accepts.
|
|
379
740
|
|
|
741
|
+
<!-- prettier-ignore-start -->
|
|
380
742
|
```javascript
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
743
|
+
const verify = guard(optional(string));
|
|
744
|
+
|
|
745
|
+
// 👍
|
|
746
|
+
verify('hello') === 'hello';
|
|
747
|
+
verify(undefined) === undefined;
|
|
748
|
+
|
|
749
|
+
// 👎
|
|
750
|
+
verify(null); // throws
|
|
751
|
+
verify(0); // throws
|
|
752
|
+
verify(42); // throws
|
|
387
753
|
```
|
|
754
|
+
<!-- prettier-ignore-end -->
|
|
388
755
|
|
|
389
756
|
A typical case where `optional` is useful is in decoding objects with optional fields:
|
|
390
757
|
|
|
@@ -410,127 +777,184 @@ Which will decode to type:
|
|
|
410
777
|
|
|
411
778
|
<a name="nullable" href="#nullable">#</a>
|
|
412
779
|
<b>nullable</b><i><T></i>(<i>Decoder<T></i>): <i>Decoder<T | null></i>
|
|
413
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
780
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/optional.js 'Source')
|
|
414
781
|
|
|
415
|
-
|
|
416
|
-
provided that you already have a decoder for <i>T</i>.
|
|
782
|
+
Accepts only the literal value `null`, or whatever the given decoder accepts.
|
|
417
783
|
|
|
784
|
+
<!-- prettier-ignore-start -->
|
|
418
785
|
```javascript
|
|
419
|
-
const
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
786
|
+
const verify = guard(nullable(string));
|
|
787
|
+
|
|
788
|
+
// 👍
|
|
789
|
+
verify('hello') === 'hello';
|
|
790
|
+
verify(null) === null;
|
|
791
|
+
|
|
792
|
+
// 👎
|
|
793
|
+
verify(undefined); // throws
|
|
794
|
+
verify(0); // throws
|
|
795
|
+
verify(42); // throws
|
|
425
796
|
```
|
|
797
|
+
<!-- prettier-ignore-end -->
|
|
426
798
|
|
|
427
799
|
---
|
|
428
800
|
|
|
429
801
|
<a name="maybe" href="#maybe">#</a> <b>maybe</b><i><T></i>(<i>Decoder<T></i>):
|
|
430
802
|
<i>Decoder<?T></i>
|
|
431
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
803
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/optional.js 'Source')
|
|
432
804
|
|
|
433
|
-
|
|
434
|
-
`undefined`**, provided that you already have a decoder for <i>T</i>.
|
|
805
|
+
Accepts only `undefined`, `null`, or whatever the given decoder accepts.
|
|
435
806
|
|
|
807
|
+
<!-- prettier-ignore-start -->
|
|
436
808
|
```javascript
|
|
437
|
-
const
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
809
|
+
const verify = guard(maybe(string));
|
|
810
|
+
|
|
811
|
+
// 👍
|
|
812
|
+
verify('hello') === 'hello';
|
|
813
|
+
verify(null) === null;
|
|
814
|
+
verify(undefined) === undefined;
|
|
815
|
+
|
|
816
|
+
// 👎
|
|
817
|
+
verify(0); // throws
|
|
818
|
+
verify(42); // throws
|
|
443
819
|
```
|
|
820
|
+
<!-- prettier-ignore-end -->
|
|
444
821
|
|
|
445
822
|
---
|
|
446
823
|
|
|
447
824
|
<a name="array" href="#array">#</a> <b>array</b><i><T></i>(<i>Decoder<T></i>):
|
|
448
825
|
<i>Decoder<Array<T>></i>
|
|
449
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
826
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/array.js 'Source')
|
|
450
827
|
|
|
451
|
-
|
|
452
|
-
already have a decoder for <i>T</i>.
|
|
828
|
+
Accepts only arrays of whatever the given decoder accepts.
|
|
453
829
|
|
|
830
|
+
<!-- prettier-ignore-start -->
|
|
454
831
|
```javascript
|
|
455
|
-
const
|
|
456
|
-
|
|
457
|
-
|
|
832
|
+
const verify = guard(array(string));
|
|
833
|
+
|
|
834
|
+
// 👍
|
|
835
|
+
verify(['hello', 'world']) === ['hello', 'world'];
|
|
836
|
+
|
|
837
|
+
// 👎
|
|
838
|
+
verify(['hello', 1.2]); // throws
|
|
458
839
|
```
|
|
840
|
+
<!-- prettier-ignore-end -->
|
|
459
841
|
|
|
460
842
|
---
|
|
461
843
|
|
|
462
844
|
<a name="nonEmptyArray" href="#nonEmptyArray">#</a>
|
|
463
845
|
<b>nonEmptyArray</b><i><T></i>(<i>Decoder<T></i>):
|
|
464
846
|
<i>Decoder<Array<T>></i>
|
|
465
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
847
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/array.js 'Source')
|
|
466
848
|
|
|
467
|
-
Like `array()`, but will
|
|
849
|
+
Like `array()`, but will reject arrays with 0 elements.
|
|
468
850
|
|
|
851
|
+
<!-- prettier-ignore-start -->
|
|
469
852
|
```javascript
|
|
470
|
-
const
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
853
|
+
const verify = guard(nonEmptyArray(string));
|
|
854
|
+
|
|
855
|
+
// 👍
|
|
856
|
+
verify(['hello', 'world']) === ['hello', 'world'];
|
|
857
|
+
|
|
858
|
+
// 👎
|
|
859
|
+
verify(['hello', 1.2]); // throws
|
|
860
|
+
verify([]); // throws
|
|
474
861
|
```
|
|
862
|
+
<!-- prettier-ignore-end -->
|
|
475
863
|
|
|
476
864
|
---
|
|
477
865
|
|
|
478
|
-
<a name="
|
|
479
|
-
|
|
480
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/tuple.js 'Source')<br />
|
|
481
|
-
<a name="tuple2" href="#tuple2">#</a> <b>tuple2</b><i><T1,
|
|
482
|
-
T2></i>(<i>Decoder<T1></i>, <i>Decoder<T2></i>): <i>Decoder<[T1,
|
|
483
|
-
T2]></i>
|
|
484
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/tuple.js 'Source')<br />
|
|
485
|
-
<a name="tuple3" href="#tuple3">#</a> <b>tuple3</b><i><T1, T2,
|
|
486
|
-
T3></i>(<i>Decoder<T1></i>, <i>Decoder<T2></i>, <i>Decoder<T3></i>):
|
|
487
|
-
<i>Decoder<[T1, T2, T3]></i>
|
|
488
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/tuple.js 'Source')<br />
|
|
489
|
-
<a name="tuple4" href="#tuple4">#</a> <b>tuple4</b><i><T1, T2, T3,
|
|
490
|
-
T4></i>(<i>Decoder<T1></i>, <i>Decoder<T2></i>, <i>Decoder<T3></i>,
|
|
491
|
-
<i>Decoder<T4></i>): <i>Decoder<[T1, T2, T3, T4]></i>
|
|
492
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/tuple.js 'Source')<br />
|
|
493
|
-
<a name="tuple5" href="#tuple5">#</a> <b>tuple5</b><i><T1, T2, T3, T4,
|
|
494
|
-
T5></i>(<i>Decoder<T1></i>, <i>Decoder<T2></i>, <i>Decoder<T3></i>,
|
|
495
|
-
<i>Decoder<T3></i>, <i>Decoder<T4></i>, <i>Decoder<T5></i>):
|
|
496
|
-
<i>Decoder<[T1, T2, T3, T4, T5]></i>
|
|
497
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/tuple.js 'Source')<br />
|
|
498
|
-
<a name="tuple6" href="#tuple6">#</a> <b>tuple6</b><i><T1, T2, T3, T4, T5,
|
|
499
|
-
T6></i>(<i>Decoder<T1></i>, <i>Decoder<T2></i>, <i>Decoder<T3></i>,
|
|
500
|
-
<i>Decoder<T4></i>, <i>Decoder<T5></i>, <i>Decoder<T6></i>):
|
|
501
|
-
<i>Decoder<[T1, T2, T3, T4, T5, T6]></i>
|
|
502
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/tuple.js 'Source')
|
|
866
|
+
<a name="poja" href="#poja">#</a> <b>poja</b>: <i>Decoder<Array<unknown>></i>
|
|
867
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/array.js 'Source')
|
|
503
868
|
|
|
504
|
-
|
|
505
|
-
you already have a decoder for <i>T1</i> and <i>T2</i>. A tuple is like an Array, but the
|
|
506
|
-
number of items in the array is fixed (two) and their types don't have to be homogeneous.
|
|
869
|
+
Accepts any array, but doesn't validate its items further.
|
|
507
870
|
|
|
871
|
+
"poja" means "plain old JavaScript array", a play on ["pojo"](#pojo).
|
|
872
|
+
|
|
873
|
+
<!-- prettier-ignore-start -->
|
|
874
|
+
```javascript
|
|
875
|
+
const verify = guard(poja);
|
|
876
|
+
|
|
877
|
+
// 👍
|
|
878
|
+
verify([1, 'hi', true]) === [1, 'hi', true];
|
|
879
|
+
verify(['hello', 'world']) === ['hello', 'world'];
|
|
880
|
+
verify([]) === [];
|
|
881
|
+
|
|
882
|
+
// 👎
|
|
883
|
+
verify({}); // throws
|
|
884
|
+
verify('hi'); // throws
|
|
885
|
+
```
|
|
886
|
+
<!-- prettier-ignore-end -->
|
|
887
|
+
|
|
888
|
+
---
|
|
889
|
+
|
|
890
|
+
<a name="tuple" href="#tuple">#</a> <b>tuple</b><i><A, B, C,
|
|
891
|
+
...></i>(<i>Decoder<A></i>, <i>Decoder<B></i>, <i>Decoder<C></i>):
|
|
892
|
+
<i>Decoder<[A, B, C, ...]></i>
|
|
893
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/tuple.js 'Source')
|
|
894
|
+
|
|
895
|
+
Accepts a tuple (an array with exactly _n_ items) of values accepted by the _n_ given
|
|
896
|
+
decoders.
|
|
897
|
+
|
|
898
|
+
<!-- prettier-ignore-start -->
|
|
508
899
|
```javascript
|
|
509
|
-
const
|
|
510
|
-
|
|
511
|
-
|
|
900
|
+
const verify = guard(tuple(string, number));
|
|
901
|
+
|
|
902
|
+
// 👍
|
|
903
|
+
verify(['hello', 1.2]) === ['hello', 1.2];
|
|
904
|
+
|
|
905
|
+
// 👎
|
|
906
|
+
verify([]); // throws, too few items
|
|
907
|
+
verify(['hello', 'world']); // throws, not the right types
|
|
908
|
+
verify(['a', 1, 'c']); // throws, too many items
|
|
512
909
|
```
|
|
910
|
+
<!-- prettier-ignore-end -->
|
|
911
|
+
|
|
912
|
+
---
|
|
913
|
+
|
|
914
|
+
<a name="set" href="#set">#</a> <b>set</b><i><T></i>(<i>Decoder<T></i>):
|
|
915
|
+
<i>Decoder<Set<T>></i>
|
|
916
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/array.js 'Source')
|
|
917
|
+
|
|
918
|
+
Similar to [`array`](#array), but returns the result as an ES6 Set.
|
|
919
|
+
|
|
920
|
+
<!-- prettier-ignore-start -->
|
|
921
|
+
```javascript
|
|
922
|
+
const verify = guard(set(string));
|
|
923
|
+
|
|
924
|
+
// 👍
|
|
925
|
+
verify(['hello', 'world']) // ≈ new Set(['hello', 'world']);
|
|
926
|
+
|
|
927
|
+
// 👎
|
|
928
|
+
verify(['hello', 1.2]); // throws
|
|
929
|
+
```
|
|
930
|
+
<!-- prettier-ignore-end -->
|
|
513
931
|
|
|
514
932
|
---
|
|
515
933
|
|
|
516
934
|
<a name="object" href="#object">#</a> <b>object</b><i><O: { [field: string]:
|
|
517
935
|
Decoder<any> }></i>(mapping: O): <i>Decoder<{ ... }></i>
|
|
518
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
936
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/object.js 'Source')
|
|
519
937
|
|
|
520
|
-
|
|
521
|
-
|
|
938
|
+
Accepts object values with fields matching the given decoders. Extra fields that exist on
|
|
939
|
+
the input object are ignored and will not be returned.
|
|
522
940
|
|
|
941
|
+
<!-- prettier-ignore-start -->
|
|
523
942
|
```javascript
|
|
524
|
-
const
|
|
943
|
+
const verify = guard(
|
|
525
944
|
object({
|
|
526
945
|
x: number,
|
|
527
946
|
y: number,
|
|
528
|
-
})
|
|
947
|
+
}),
|
|
529
948
|
);
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
949
|
+
|
|
950
|
+
// 👍
|
|
951
|
+
verify({ x: 1, y: 2 }) === { x: 1, y: 2 };
|
|
952
|
+
verify({ x: 1, y: 2, z: 3 }) === { x: 1, y: 2 }; // ⚠️ extra field `z` not returned!
|
|
953
|
+
|
|
954
|
+
// 👎
|
|
955
|
+
verify({ x: 1 }); // throws, missing field `y`
|
|
533
956
|
```
|
|
957
|
+
<!-- prettier-ignore-end -->
|
|
534
958
|
|
|
535
959
|
For more information, see also
|
|
536
960
|
[The difference between `object`, `exact`, and `inexact`](#the-difference-between-object-exact-and-inexact).
|
|
@@ -539,21 +963,28 @@ For more information, see also
|
|
|
539
963
|
|
|
540
964
|
<a name="exact" href="#exact">#</a> <b>exact</b><i><O: { [field: string]:
|
|
541
965
|
Decoder<any> }></i>(mapping: O): <i>Decoder<{ ... }></i>
|
|
542
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
966
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/object.js 'Source')
|
|
543
967
|
|
|
544
|
-
Like `object()`, but will
|
|
968
|
+
Like `object()`, but will reject inputs that contain extra keys that are not specified
|
|
969
|
+
explicitly.
|
|
545
970
|
|
|
971
|
+
<!-- prettier-ignore-start -->
|
|
546
972
|
```javascript
|
|
547
|
-
const
|
|
973
|
+
const verify = guard(
|
|
548
974
|
exact({
|
|
549
975
|
x: number,
|
|
550
976
|
y: number,
|
|
551
|
-
})
|
|
977
|
+
}),
|
|
552
978
|
);
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
979
|
+
|
|
980
|
+
// 👍
|
|
981
|
+
verify({ x: 1, y: 2 }) === { x: 1, y: 2 };
|
|
982
|
+
|
|
983
|
+
// 👎
|
|
984
|
+
verify({ x: 1, y: 2, z: 3 }); // throws, extra field `z` not allowed
|
|
985
|
+
verify({ x: 1 }); // throws, missing field `y`
|
|
556
986
|
```
|
|
987
|
+
<!-- prettier-ignore-end -->
|
|
557
988
|
|
|
558
989
|
For more information, see also
|
|
559
990
|
[The difference between `object`, `exact`, and `inexact`](#the-difference-between-object-exact-and-inexact).
|
|
@@ -562,88 +993,116 @@ For more information, see also
|
|
|
562
993
|
|
|
563
994
|
<a name="inexact" href="#inexact">#</a> <b>inexact</b><i><O: { [field: string]:
|
|
564
995
|
Decoder<any> }></i>(mapping: O): <i>Decoder<{ ... }></i>
|
|
565
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
996
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/object.js 'Source')
|
|
566
997
|
|
|
567
|
-
Like `object()`, but will
|
|
568
|
-
|
|
998
|
+
Like `object()`, but will pass through any extra fields on the input object unvalidated
|
|
999
|
+
that will thus be of `unknown` type statically.
|
|
569
1000
|
|
|
1001
|
+
<!-- prettier-ignore-start -->
|
|
570
1002
|
```javascript
|
|
571
|
-
const
|
|
1003
|
+
const verify = guard(
|
|
572
1004
|
inexact({
|
|
573
1005
|
x: number,
|
|
574
|
-
})
|
|
1006
|
+
}),
|
|
575
1007
|
);
|
|
576
1008
|
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
1009
|
+
// 👍
|
|
1010
|
+
verify({ x: 1, y: 2 }) === { x: 1, y: 2 };
|
|
1011
|
+
verify({ x: 1, y: 2, z: 3 }) === { x: 1, y: 2, z: 3 };
|
|
1012
|
+
|
|
1013
|
+
// 👎
|
|
1014
|
+
verify({ x: 1 }); // throws, missing field `y`
|
|
580
1015
|
```
|
|
1016
|
+
<!-- prettier-ignore-end -->
|
|
581
1017
|
|
|
582
1018
|
For more information, see also
|
|
583
1019
|
[The difference between `object`, `exact`, and `inexact`](#the-difference-between-object-exact-and-inexact).
|
|
584
1020
|
|
|
585
1021
|
---
|
|
586
1022
|
|
|
587
|
-
<a name="
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/mapping.js 'Source')
|
|
1023
|
+
<a name="pojo" href="#pojo">#</a> <b>pojo</b>: <i>Decoder<{ [key: string]: unknown
|
|
1024
|
+
}></i>
|
|
1025
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/object.js 'Source')
|
|
591
1026
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
The main difference between `object()` and `mapping()` is that you'd typically use
|
|
596
|
-
`object()` if this is a record-like object, where you know all the field names and the
|
|
597
|
-
values are heterogeneous. Whereas with Mappings the keys are typically unknown and the
|
|
598
|
-
values homogeneous.
|
|
1027
|
+
Accepts any "plain old JavaScript object", but doesn't validate its keys or values
|
|
1028
|
+
further.
|
|
599
1029
|
|
|
1030
|
+
<!-- prettier-ignore-start -->
|
|
600
1031
|
```javascript
|
|
601
|
-
const
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
1032
|
+
const verify = guard(pojo);
|
|
1033
|
+
|
|
1034
|
+
// 👍
|
|
1035
|
+
verify({}) === {};
|
|
1036
|
+
verify({ name: 'hi' }) === { name: 'hi' };
|
|
1037
|
+
|
|
1038
|
+
// 👎
|
|
1039
|
+
verify('hi'); // throws
|
|
1040
|
+
verify([]); // throws
|
|
1041
|
+
verify(new Date()); // throws
|
|
1042
|
+
verify(null); // throws
|
|
612
1043
|
```
|
|
1044
|
+
<!-- prettier-ignore-end -->
|
|
613
1045
|
|
|
614
1046
|
---
|
|
615
1047
|
|
|
616
1048
|
<a name="dict" href="#dict">#</a> <b>dict</b><i><T></i>(<i>Decoder<T></i>):
|
|
617
1049
|
<i>Decoder<{ [string]: <T>}></i>
|
|
618
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
1050
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/object.js 'Source')
|
|
1051
|
+
|
|
1052
|
+
Accepts objects where all values match the given decoder, and returns the result as a
|
|
1053
|
+
`{ [string]: T }`.
|
|
619
1054
|
|
|
620
|
-
|
|
1055
|
+
The main difference between `object()` and `dict()` is that you'd typically use `object()`
|
|
1056
|
+
if this is a record-like object, where all field names are known and the values are
|
|
1057
|
+
heterogeneous. Whereas with `dict()` the keys are typically dynamic and the values
|
|
1058
|
+
homogeneous, like in a dictionary, a lookup table, or a cache.
|
|
621
1059
|
|
|
622
1060
|
```javascript
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
}
|
|
1061
|
+
const verify = guard(dict(person)); // Assume you have a "person" decoder already
|
|
1062
|
+
|
|
1063
|
+
// 👍
|
|
1064
|
+
verify({
|
|
1065
|
+
1: { name: 'Alice' },
|
|
1066
|
+
2: { name: 'Bob' },
|
|
1067
|
+
3: { name: 'Charlie' },
|
|
1068
|
+
}); // ≈ {
|
|
1069
|
+
// "1": { name: "Alice" },
|
|
1070
|
+
// "2": { name: "Bob" },
|
|
1071
|
+
// "3": { name: "Charlie" },
|
|
1072
|
+
// }
|
|
629
1073
|
```
|
|
630
1074
|
|
|
631
|
-
|
|
1075
|
+
---
|
|
1076
|
+
|
|
1077
|
+
<a name="mapping" href="#mapping">#</a>
|
|
1078
|
+
<b>mapping</b><i><T></i>(<i>Decoder<T></i>): <i>Decoder<Map<string,
|
|
1079
|
+
T>></i>
|
|
1080
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/object.js 'Source')
|
|
1081
|
+
|
|
1082
|
+
Like `dict()`, but returns the result as a `Map<string, T>` instead.
|
|
632
1083
|
|
|
633
1084
|
```javascript
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
}
|
|
1085
|
+
const verify = guard(mapping(person)); // Assume you have a "person" decoder already
|
|
1086
|
+
|
|
1087
|
+
// 👍
|
|
1088
|
+
verify({
|
|
1089
|
+
1: { name: 'Alice' },
|
|
1090
|
+
2: { name: 'Bob' },
|
|
1091
|
+
3: { name: 'Charlie' },
|
|
1092
|
+
});
|
|
1093
|
+
// ≈ Map([
|
|
1094
|
+
// ['1', { name: 'Alice' }],
|
|
1095
|
+
// ['2', { name: 'Bob' }],
|
|
1096
|
+
// ['3', { name: 'Charlie' }],
|
|
1097
|
+
// ]);
|
|
639
1098
|
```
|
|
640
1099
|
|
|
641
1100
|
---
|
|
642
1101
|
|
|
643
1102
|
<a name="json" href="#json">#</a> <b>json</b>: <i>Decoder<JSONValue></i>
|
|
644
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
1103
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/json.js 'Source')
|
|
645
1104
|
|
|
646
|
-
|
|
1105
|
+
Accepts any value that's a valid JSON value:
|
|
647
1106
|
|
|
648
1107
|
- `null`
|
|
649
1108
|
- `string`
|
|
@@ -653,8 +1112,10 @@ Returns a decoder capable of decoding **any valid JSON value**:
|
|
|
653
1112
|
- `Array<JSONValue>`
|
|
654
1113
|
|
|
655
1114
|
```javascript
|
|
656
|
-
const
|
|
657
|
-
|
|
1115
|
+
const verify = guard(json);
|
|
1116
|
+
|
|
1117
|
+
// 👍
|
|
1118
|
+
verify({
|
|
658
1119
|
name: 'Amir',
|
|
659
1120
|
age: 27,
|
|
660
1121
|
admin: true,
|
|
@@ -669,94 +1130,105 @@ Any value returned by `JSON.parse()` should decode without failure.
|
|
|
669
1130
|
|
|
670
1131
|
<a name="jsonObject" href="#jsonObject">#</a> <b>jsonObject</b>:
|
|
671
1132
|
<i>Decoder<JSONObject></i>
|
|
672
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
1133
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/json.js 'Source')
|
|
673
1134
|
|
|
674
1135
|
Like `json`, but will only decode when the JSON value is an object.
|
|
675
1136
|
|
|
1137
|
+
<!-- prettier-ignore-start -->
|
|
676
1138
|
```javascript
|
|
677
|
-
const
|
|
678
|
-
mydecoder({}); // OK
|
|
679
|
-
mydecoder({ name: 'Amir' }); // OK
|
|
1139
|
+
const verify = guard(json);
|
|
680
1140
|
|
|
681
|
-
//
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
1141
|
+
// 👍
|
|
1142
|
+
verify({}); // ≈ {}
|
|
1143
|
+
verify({ name: 'Amir' }); // ≈ { name: 'Amir' }
|
|
1144
|
+
|
|
1145
|
+
// 👎
|
|
1146
|
+
verify([]); // throws
|
|
1147
|
+
verify([{ name: 'Alice' }]); // throws
|
|
1148
|
+
verify('hello'); // throws
|
|
1149
|
+
verify(null); // throws
|
|
686
1150
|
```
|
|
1151
|
+
<!-- prettier-ignore-end -->
|
|
687
1152
|
|
|
688
1153
|
---
|
|
689
1154
|
|
|
690
1155
|
<a name="jsonArray" href="#jsonArray">#</a> <b>jsonArray</b>:
|
|
691
1156
|
<i>Decoder<JSONArray></i>
|
|
692
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
1157
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/json.js 'Source')
|
|
693
1158
|
|
|
694
1159
|
Like `json`, but will only decode when the JSON value is an array.
|
|
695
1160
|
|
|
1161
|
+
<!-- prettier-ignore-start -->
|
|
696
1162
|
```javascript
|
|
697
|
-
const
|
|
698
|
-
|
|
699
|
-
|
|
1163
|
+
const verify = guard(json);
|
|
1164
|
+
|
|
1165
|
+
// 👍
|
|
1166
|
+
verify([]); // ≈ []
|
|
1167
|
+
verify([{ name: 'Amir' }]); // ≈ [{ name: 'Amir' }]
|
|
700
1168
|
|
|
701
|
-
//
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
1169
|
+
// 👎
|
|
1170
|
+
verify({}); // throws
|
|
1171
|
+
verify({ name: 'Alice' }); // throws
|
|
1172
|
+
verify('hello'); // throws
|
|
1173
|
+
verify(null); // throws
|
|
706
1174
|
```
|
|
1175
|
+
<!-- prettier-ignore-end -->
|
|
707
1176
|
|
|
708
1177
|
---
|
|
709
1178
|
|
|
710
|
-
<a name="either" href="#either">#</a> <b>either</b><i><
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
714
|
-
<a name="either2" href="#either2">#</a> <b>either2</b><i><T1,
|
|
715
|
-
T2></i>(<i>Decoder<T1></i>, <i>Decoder<T2></i>): <i>Decoder<T1 |
|
|
716
|
-
T2></i><br />
|
|
717
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/either.js 'Source')<br />
|
|
718
|
-
<a name="either3" href="#either3">#</a> <b>either3</b><i><T1, T2,
|
|
719
|
-
T3></i>(<i>Decoder<T1></i>, <i>Decoder<T2></i>, <i>Decoder<T3></i>):
|
|
720
|
-
<i>Decoder<T1 | T2 | T3></i>
|
|
721
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/either.js 'Source')<br /> ...
|
|
1179
|
+
<a name="either" href="#either">#</a> <b>either</b><i><A, B, C,
|
|
1180
|
+
...></i>(<i>Decoder<A></i>, <i>Decoder<B></i>, <i>Decoder<C></i>,
|
|
1181
|
+
...): <i>Decoder<A | B | C | ...></i><br />
|
|
1182
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/either.js 'Source')<br />
|
|
722
1183
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
until 9 (either, either3, either4, ..., either9).
|
|
1184
|
+
Accepts any value that is accepted by any of the given decoders. The decoders are
|
|
1185
|
+
attempted on the input in given order. The first one that accepts the input "wins".
|
|
726
1186
|
|
|
1187
|
+
<!-- prettier-ignore-start -->
|
|
727
1188
|
```javascript
|
|
728
|
-
const
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
1189
|
+
const verify = guard(either(number, string));
|
|
1190
|
+
|
|
1191
|
+
// 👍
|
|
1192
|
+
verify('hello world') === 'hello world';
|
|
1193
|
+
verify(123) === 123;
|
|
1194
|
+
|
|
1195
|
+
// 👎
|
|
1196
|
+
verify(false); // throws
|
|
732
1197
|
```
|
|
1198
|
+
<!-- prettier-ignore-end -->
|
|
1199
|
+
|
|
1200
|
+
**NOTE to Flow users:** In Flow, there is a max of 16 arguments with this construct. (This
|
|
1201
|
+
is no problem in TypeScript.) If you hit the 16 argument limit, you can work around that
|
|
1202
|
+
by stacking, e.g. do `either(<15 arguments here>, either(...))`.
|
|
733
1203
|
|
|
734
1204
|
---
|
|
735
1205
|
|
|
736
|
-
<a name="
|
|
737
|
-
(Decoder<T> | Decoder<V> | ...) }></i>(field: string, mapping: O):
|
|
1206
|
+
<a name="taggedUnion" href="#taggedUnion">#</a> <b>taggedUnion</b><i><O: { [field:
|
|
1207
|
+
string]: (Decoder<T> | Decoder<V> | ...) }></i>(field: string, mapping: O):
|
|
738
1208
|
<i>Decoder<T | V | ...></i>
|
|
739
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
1209
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/dispatch.js 'Source')
|
|
1210
|
+
|
|
1211
|
+
**NOTE:** In decoders@1.x, this was called `dispatch()`.
|
|
740
1212
|
|
|
741
|
-
Like
|
|
742
|
-
|
|
1213
|
+
Like `either`, but only for building unions of object types with a common field (like a
|
|
1214
|
+
`type` field) that lets you distinguish members.
|
|
743
1215
|
|
|
744
1216
|
The following two decoders are effectively equivalent:
|
|
745
1217
|
|
|
746
1218
|
```javascript
|
|
747
|
-
type Rect = {
|
|
748
|
-
type Circle = {
|
|
749
|
-
//
|
|
750
|
-
//
|
|
1219
|
+
type Rect = { __type: 'rect', x: number, y: number, width: number, height: number };
|
|
1220
|
+
type Circle = { __type: 'circle', cx: number, cy: number, r: number };
|
|
1221
|
+
// ^^^^^^
|
|
1222
|
+
// Field that defines which decoder to pick
|
|
751
1223
|
// vvvvvv
|
|
752
|
-
const shape1: Decoder<Rect | Circle> =
|
|
1224
|
+
const shape1: Decoder<Rect | Circle> = taggedUnion('__type', { rect, circle });
|
|
753
1225
|
const shape2: Decoder<Rect | Circle> = either(rect, circle);
|
|
754
1226
|
```
|
|
755
1227
|
|
|
756
|
-
But using `
|
|
757
|
-
reason is that `
|
|
758
|
-
field here, and based on that value, pick which decoder to invoke. Error messages
|
|
759
|
-
then also be tailored to the specific decoder.
|
|
1228
|
+
But using `taggedUnion()` will typically be more runtime-efficient than using `either()`.
|
|
1229
|
+
The reason is that `taggedUnion()` will first do minimal work to "look ahead" into the
|
|
1230
|
+
`type` field here, and based on that value, pick which decoder to invoke. Error messages
|
|
1231
|
+
will then also be tailored to the specific decoder.
|
|
760
1232
|
|
|
761
1233
|
The `either()` version will instead try each decoder in turn until it finds one that
|
|
762
1234
|
matches. If none of the alternatives match, it needs to report all errors, which is
|
|
@@ -766,19 +1238,24 @@ sometimes confusing.
|
|
|
766
1238
|
|
|
767
1239
|
<a name="oneOf" href="#oneOf">#</a> <b>oneOf</b><i><T></i>(<i>Array<T></i>):
|
|
768
1240
|
<i>Decoder<T></i>
|
|
769
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
1241
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/either.js 'Source')<br />
|
|
770
1242
|
|
|
771
|
-
|
|
772
|
-
given constants. The returned value will always be one of the given constants at runtime.
|
|
1243
|
+
Accepts any value that is strictly-equal (using `===`) to one of the specified values.
|
|
773
1244
|
|
|
1245
|
+
<!-- prettier-ignore-start -->
|
|
774
1246
|
```javascript
|
|
775
|
-
const
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
1247
|
+
const verify = guard(oneOf(['foo', 'bar', 3]));
|
|
1248
|
+
|
|
1249
|
+
// 👍
|
|
1250
|
+
verify('foo') === 'foo';
|
|
1251
|
+
verify(3) === 3;
|
|
1252
|
+
|
|
1253
|
+
// 👎
|
|
1254
|
+
verify('hello'); // throws
|
|
1255
|
+
verify(4); // throws
|
|
1256
|
+
verify(false); // throws
|
|
781
1257
|
```
|
|
1258
|
+
<!-- prettier-ignore-end -->
|
|
782
1259
|
|
|
783
1260
|
For example, given an array of strings, like so:
|
|
784
1261
|
|
|
@@ -795,72 +1272,142 @@ annotate the type. Either by doing `oneOf([('foo': 'foo'), ('bar': 'bar')])`, or
|
|
|
795
1272
|
|
|
796
1273
|
<a name="instanceOf" href="#instanceOf">#</a>
|
|
797
1274
|
<b>instanceOf</b><i><T></i>(<i>Class<T></i>): <i>Decoder<T></i>
|
|
798
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
1275
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/instanceOf.js 'Source')<br />
|
|
799
1276
|
|
|
800
|
-
|
|
1277
|
+
Accepts any value that is an `instanceof` the given class.
|
|
801
1278
|
|
|
802
1279
|
> **NOTE: Help wanted!** The TypeScript annotation for this decoder needs help! If you
|
|
803
1280
|
> know how to express it, please submit a PR. See
|
|
804
|
-
> https://github.com/nvie/decoders/blob/
|
|
1281
|
+
> https://github.com/nvie/decoders/blob/main/src/core/instanceOf.d.ts
|
|
805
1282
|
|
|
1283
|
+
<!-- prettier-ignore-start -->
|
|
806
1284
|
```javascript
|
|
807
|
-
const
|
|
1285
|
+
const verify = guard(instanceOf(Error));
|
|
1286
|
+
|
|
1287
|
+
// 👍
|
|
808
1288
|
const value = new Error('foo');
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
1289
|
+
verify(value) === value;
|
|
1290
|
+
|
|
1291
|
+
// 👎
|
|
1292
|
+
verify('foo'); // throws
|
|
1293
|
+
verify(3); // throws
|
|
812
1294
|
```
|
|
1295
|
+
<!-- prettier-ignore-end -->
|
|
813
1296
|
|
|
814
1297
|
---
|
|
815
1298
|
|
|
816
|
-
<a name="
|
|
817
|
-
<i
|
|
818
|
-
|
|
1299
|
+
<a name="transform" href="#transform">#</a> <b>transform</b><i><T,
|
|
1300
|
+
V></i>(<i>Decoder<T></i>, <i><T></i> => <i><V></i>):
|
|
1301
|
+
<i>Decoder<V></i>
|
|
1302
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/utils.js 'Source')<br />
|
|
819
1303
|
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
the failure reason.
|
|
1304
|
+
Accepts any value the given decoder accepts, and on success, will call the mapper value
|
|
1305
|
+
**on the decoded result**. If the mapper function throws an error, the whole decoder will
|
|
1306
|
+
fail using the error message as the failure reason.
|
|
824
1307
|
|
|
1308
|
+
<!-- prettier-ignore-start -->
|
|
825
1309
|
```javascript
|
|
826
|
-
const upper =
|
|
1310
|
+
const upper = transform(string, (s) => s.toUpperCase());
|
|
1311
|
+
const verify = guard(upper);
|
|
1312
|
+
|
|
1313
|
+
// 👍
|
|
1314
|
+
verify('foo') === 'FOO';
|
|
827
1315
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
mydecoder('foo') === 'FOO';
|
|
1316
|
+
// 👎
|
|
1317
|
+
verify(4); // throws
|
|
831
1318
|
```
|
|
1319
|
+
<!-- prettier-ignore-end -->
|
|
832
1320
|
|
|
833
1321
|
---
|
|
834
1322
|
|
|
835
1323
|
<a name="compose" href="#compose">#</a> <b>compose</b><i><T,
|
|
836
1324
|
V></i>(<i>Decoder<T></i>, <i>Decoder<V, T></i>): <i>Decoder<V></i>
|
|
837
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
1325
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/composition.js 'Source')<br />
|
|
1326
|
+
|
|
1327
|
+
Given a decoder for _T_ and another one for _V_-given-a-_T_. Will first decode the input
|
|
1328
|
+
using the first decoder, and _if okay_, pass the result on to the second decoder. The
|
|
1329
|
+
second decoder will thus be able to make more assumptions about its input value, i.e. it
|
|
1330
|
+
can know what type the input value is (`T` instead of `unknown`).
|
|
1331
|
+
|
|
1332
|
+
This is an advanced decoder, typically only useful for authors of decoders. It's not
|
|
1333
|
+
recommended to rely on this decoder directly for normal usage.
|
|
1334
|
+
|
|
1335
|
+
---
|
|
1336
|
+
|
|
1337
|
+
<a name="predicate" href="#predicate">#</a>
|
|
1338
|
+
<b>predicate</b><i><T></i>(<i>Decoder<T></i>, <i><T> => boolean</i>,
|
|
1339
|
+
string): <i>Decoder<T></i>
|
|
1340
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/composition.js 'Source')<br />
|
|
838
1341
|
|
|
839
|
-
|
|
840
|
-
call the _V_ decoder **on the original value**. This differs from `map()` in that it was
|
|
841
|
-
access to the original value, but may assume the type value is already refined by the
|
|
842
|
-
first decoder.
|
|
1342
|
+
Accepts values that are accepted by the decoder _and_ also pass the predicate function.
|
|
843
1343
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
1344
|
+
<!-- prettier-ignore-start -->
|
|
1345
|
+
```typescript
|
|
1346
|
+
const odd = predicate(
|
|
1347
|
+
number,
|
|
1348
|
+
(n) => n % 2 !== 0,
|
|
1349
|
+
'Must be odd'
|
|
1350
|
+
);
|
|
1351
|
+
const verify = guard(odd);
|
|
1352
|
+
|
|
1353
|
+
// 👍
|
|
1354
|
+
verify(3) === 3;
|
|
1355
|
+
|
|
1356
|
+
// 👎
|
|
1357
|
+
verify('hi'); // throws: not a number
|
|
1358
|
+
verify(42); // throws: not an odd number
|
|
1359
|
+
```
|
|
1360
|
+
<!-- prettier-ignore-end -->
|
|
1361
|
+
|
|
1362
|
+
In TypeScript, if you provide a predicate that also doubles as a [type
|
|
1363
|
+
predicate][type-predicates], then this will be reflected in the return type, too.
|
|
1364
|
+
|
|
1365
|
+
---
|
|
1366
|
+
|
|
1367
|
+
<a name="prep" href="#prep">#</a> <b>prep</b><i><T, I></i>(<i>unknown => I</i>,
|
|
1368
|
+
<i>Decoder<T, I></i>): <i>Decoder<T></i>
|
|
1369
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/composition.js 'Source')<br />
|
|
1370
|
+
|
|
1371
|
+
Pre-process the raw data input before passing it into the decoder. This gives you the
|
|
1372
|
+
ability to arbitrarily customize the input on the fly before passing it to the decoder. Of
|
|
1373
|
+
course, the input value at that point is still of `unknown` type, so you will have to deal
|
|
1374
|
+
with that accordingly.
|
|
1375
|
+
|
|
1376
|
+
<!-- prettier-ignore-start -->
|
|
1377
|
+
```typescript
|
|
1378
|
+
const verify = prep(
|
|
1379
|
+
// Will convert any input to an int first, before feeding it to
|
|
1380
|
+
// positiveInteger. This will effectively also allow numeric strings
|
|
1381
|
+
// to be accepted (and returned) as integers. If this ever throws,
|
|
1382
|
+
// then the error message will be what gets annotated on the input.
|
|
1383
|
+
x => parseInt(x),
|
|
1384
|
+
positiveInteger,
|
|
1385
|
+
);
|
|
1386
|
+
|
|
1387
|
+
// 👍
|
|
1388
|
+
verify(42) === 42;
|
|
1389
|
+
verify('3') === 3;
|
|
1390
|
+
|
|
1391
|
+
// 👎
|
|
1392
|
+
verify('-3'); // throws: not a positive number
|
|
1393
|
+
verify('hi'); // throws: not a number
|
|
1394
|
+
```
|
|
1395
|
+
<!-- prettier-ignore-end -->
|
|
848
1396
|
|
|
849
1397
|
---
|
|
850
1398
|
|
|
851
1399
|
<a name="describe" href="#describe">#</a>
|
|
852
1400
|
<b>describe</b><i><T></i>(<i>Decoder<T></i>, <i>string</i>):
|
|
853
1401
|
<i>Decoder<T></i>
|
|
854
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
1402
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/describe.js 'Source')<br />
|
|
855
1403
|
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
low-level/technical errors.
|
|
1404
|
+
Uses the given decoder, but will use an alternative error message in case it rejects. This
|
|
1405
|
+
can be used to simplify or shorten otherwise long or low-level/technical errors.
|
|
859
1406
|
|
|
860
1407
|
```javascript
|
|
861
1408
|
const vowel = describe(
|
|
862
1409
|
either5(constant('a'), constant('e'), constant('i'), constant('o'), constant('u')),
|
|
863
|
-
'Must be vowel'
|
|
1410
|
+
'Must be vowel',
|
|
864
1411
|
);
|
|
865
1412
|
```
|
|
866
1413
|
|
|
@@ -868,7 +1415,7 @@ const vowel = describe(
|
|
|
868
1415
|
|
|
869
1416
|
<a name="lazy" href="#lazy">#</a> <b>lazy</b><i><T></i>(() =>
|
|
870
1417
|
<i>Decoder<T></i>): <i>Decoder<T></i>
|
|
871
|
-
[<>](https://github.com/nvie/decoders/blob/
|
|
1418
|
+
[<>](https://github.com/nvie/decoders/blob/main/src/core/lazy.js 'Source')<br />
|
|
872
1419
|
|
|
873
1420
|
Lazily evaluate the given decoder. This is useful to build self-referential types for
|
|
874
1421
|
recursive data structures. Example:
|
|
@@ -916,16 +1463,16 @@ And a runtime input of:
|
|
|
916
1463
|
}
|
|
917
1464
|
```
|
|
918
1465
|
|
|
919
|
-
| | Extra properties | Output value | Inferred type
|
|
920
|
-
| ---------------- | ---------------- | ------------------------------ |
|
|
921
|
-
| `object(thing)` | discarded | `{a: "hi", b: 42}` | `{a: string, b: number}`
|
|
922
|
-
| `exact(thing)` | not allowed |
|
|
923
|
-
| `inexact(thing)` | retained | `{a: "hi", b: 42, c: "extra"}` | `{a: string, b: number, [string]:
|
|
1466
|
+
| | Extra properties | Output value | Inferred type |
|
|
1467
|
+
| ---------------- | ---------------- | ------------------------------ | ------------------------------------------- |
|
|
1468
|
+
| `object(thing)` | discarded | `{a: "hi", b: 42}` | `{a: string, b: number}` |
|
|
1469
|
+
| `exact(thing)` | not allowed | n/a (rejected) | `{a: string, b: number}` |
|
|
1470
|
+
| `inexact(thing)` | retained | `{a: "hi", b: 42, c: "extra"}` | `{a: string, b: number, [string]: unknown}` |
|
|
924
1471
|
|
|
925
1472
|
### Building custom decoders
|
|
926
1473
|
|
|
927
|
-
There are two main building blocks for defining your own custom decoders: `
|
|
928
|
-
`compose()`.
|
|
1474
|
+
There are two main building blocks for defining your own custom decoders: `transform()`
|
|
1475
|
+
and `compose()`.
|
|
929
1476
|
|
|
930
1477
|
There are roughly 3 use cases that you will want to use:
|
|
931
1478
|
|
|
@@ -940,18 +1487,18 @@ There are roughly 3 use cases that you will want to use:
|
|
|
940
1487
|
To read one type from the input, but return another, use:
|
|
941
1488
|
|
|
942
1489
|
```js
|
|
943
|
-
const numericString: Decoder<number> =
|
|
1490
|
+
const numericString: Decoder<number> = transform(
|
|
944
1491
|
// At runtime, expect to read a string...
|
|
945
1492
|
string,
|
|
946
1493
|
// ...but return it as a number
|
|
947
|
-
(s) => Number(s)
|
|
1494
|
+
(s) => Number(s),
|
|
948
1495
|
);
|
|
949
1496
|
```
|
|
950
1497
|
|
|
951
1498
|
To read one type, but change its value before returning:
|
|
952
1499
|
|
|
953
1500
|
```js
|
|
954
|
-
const upperCase: Decoder<string> =
|
|
1501
|
+
const upperCase: Decoder<string> = transform(string, (s) => s.toUpperCase());
|
|
955
1502
|
```
|
|
956
1503
|
|
|
957
1504
|
**WARNING:** While you can map anything to anything, it's typically **NOT A GOOD IDEA to
|
|
@@ -962,15 +1509,15 @@ business logic outside decoders makes them more reusable and composable.
|
|
|
962
1509
|
#### Adding predicates
|
|
963
1510
|
|
|
964
1511
|
The easiest way to decode using an existing decoder, but enforcing extra runtime checks on
|
|
965
|
-
their values is by
|
|
1512
|
+
their values is by wrapping it in a `predicate(...)` construction:
|
|
966
1513
|
|
|
967
1514
|
```js
|
|
968
|
-
const odd =
|
|
969
|
-
|
|
970
|
-
predicate((n) => n % 2 !== 0, 'Must be odd')
|
|
971
|
-
);
|
|
972
|
-
const shortString = compose(
|
|
973
|
-
string,
|
|
974
|
-
predicate((s) => s.length < 8, 'Must be less than 8 chars')
|
|
975
|
-
);
|
|
1515
|
+
const odd = predicate(integer, (n) => n % 2 !== 0, 'Must be odd');
|
|
1516
|
+
const shortString = predicate(string, (s) => s.length < 8, 'Must be less than 8 chars');
|
|
976
1517
|
```
|
|
1518
|
+
|
|
1519
|
+
[date-api]:
|
|
1520
|
+
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
|
|
1521
|
+
[iso8601-fmt]: https://en.wikipedia.org/wiki/ISO_8601
|
|
1522
|
+
[type-predicates]:
|
|
1523
|
+
https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates
|