decoders 2.0.0-beta11 → 2.0.0-beta12
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/Decoder.d.ts +1 -1
- package/Decoder.js +13 -3
- package/Decoder.js.flow +17 -5
- package/Decoder.mjs +13 -3
- package/lib/basics.d.ts +24 -0
- package/lib/basics.js +47 -22
- package/lib/basics.js.flow +43 -15
- package/lib/basics.mjs +38 -13
- package/lib/objects.js.flow +4 -4
- package/package.json +1 -1
package/Decoder.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export type DecodeFn<T, I = unknown> = (
|
|
|
11
11
|
) => DecodeResult<T>;
|
|
12
12
|
|
|
13
13
|
export interface Decoder<T> {
|
|
14
|
-
verify(blob: unknown, formatterFn?: (ann: Annotation) => string): T;
|
|
14
|
+
verify(blob: unknown, formatterFn?: (ann: Annotation) => string | Error): T;
|
|
15
15
|
value(blob: unknown): T | undefined;
|
|
16
16
|
decode(blob: unknown): DecodeResult<T>;
|
|
17
17
|
refine<N extends T>(predicate: (value: T) => value is N, msg: string): Decoder<N>;
|
package/Decoder.js
CHANGED
|
@@ -64,10 +64,20 @@ function define(decodeFn) {
|
|
|
64
64
|
if (result.ok) {
|
|
65
65
|
return result.value;
|
|
66
66
|
} else {
|
|
67
|
-
|
|
67
|
+
// Formatters may return a string or an error for convenience of
|
|
68
|
+
// writing them. If it already returns an Error, throw it
|
|
69
|
+
// unmodified. If it returns a string, wrap it in a "Decoding
|
|
70
|
+
// error" instance from it and throw that.
|
|
71
|
+
var strOrErr = formatter(result.error);
|
|
68
72
|
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
if (typeof strOrErr === 'string') {
|
|
74
|
+
var _err = new Error('\n' + strOrErr);
|
|
75
|
+
|
|
76
|
+
_err.name = 'Decoding error';
|
|
77
|
+
throw _err;
|
|
78
|
+
} else {
|
|
79
|
+
throw strOrErr;
|
|
80
|
+
}
|
|
71
81
|
}
|
|
72
82
|
}
|
|
73
83
|
/**
|
package/Decoder.js.flow
CHANGED
|
@@ -32,7 +32,7 @@ export type DecodeFn<T, I = mixed> = (
|
|
|
32
32
|
export type DecoderType<D> = $Call<<T>(Decoder<T>) => T, D>;
|
|
33
33
|
|
|
34
34
|
export type Decoder<T> = {|
|
|
35
|
-
verify(blob: mixed, formatterFn?: (Annotation) => string): T,
|
|
35
|
+
verify(blob: mixed, formatterFn?: (Annotation) => string | Error): T,
|
|
36
36
|
value(blob: mixed): T | void,
|
|
37
37
|
decode(blob: mixed): DecodeResult<T>,
|
|
38
38
|
refine(predicateFn: (value: T) => boolean, errmsg: string): Decoder<T>,
|
|
@@ -88,14 +88,26 @@ export function define<T>(decodeFn: DecodeFn<T>): Decoder<T> {
|
|
|
88
88
|
* it. When accepted, returns the decoded `T` value directly. Otherwise
|
|
89
89
|
* fail with a runtime error.
|
|
90
90
|
*/
|
|
91
|
-
function verify(
|
|
91
|
+
function verify(
|
|
92
|
+
blob: mixed,
|
|
93
|
+
formatter: (Annotation) => string | Error = formatInline,
|
|
94
|
+
): T {
|
|
92
95
|
const result = decode(blob);
|
|
93
96
|
if (result.ok) {
|
|
94
97
|
return result.value;
|
|
95
98
|
} else {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
// Formatters may return a string or an error for convenience of
|
|
100
|
+
// writing them. If it already returns an Error, throw it
|
|
101
|
+
// unmodified. If it returns a string, wrap it in a "Decoding
|
|
102
|
+
// error" instance from it and throw that.
|
|
103
|
+
const strOrErr = formatter(result.error);
|
|
104
|
+
if (typeof strOrErr === 'string') {
|
|
105
|
+
const err = new Error('\n' + strOrErr);
|
|
106
|
+
err.name = 'Decoding error';
|
|
107
|
+
throw err;
|
|
108
|
+
} else {
|
|
109
|
+
throw strOrErr;
|
|
110
|
+
}
|
|
99
111
|
}
|
|
100
112
|
}
|
|
101
113
|
|
package/Decoder.mjs
CHANGED
|
@@ -57,10 +57,20 @@ export function define(decodeFn) {
|
|
|
57
57
|
if (result.ok) {
|
|
58
58
|
return result.value;
|
|
59
59
|
} else {
|
|
60
|
-
|
|
60
|
+
// Formatters may return a string or an error for convenience of
|
|
61
|
+
// writing them. If it already returns an Error, throw it
|
|
62
|
+
// unmodified. If it returns a string, wrap it in a "Decoding
|
|
63
|
+
// error" instance from it and throw that.
|
|
64
|
+
var strOrErr = formatter(result.error);
|
|
61
65
|
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
if (typeof strOrErr === 'string') {
|
|
67
|
+
var _err = new Error('\n' + strOrErr);
|
|
68
|
+
|
|
69
|
+
_err.name = 'Decoding error';
|
|
70
|
+
throw _err;
|
|
71
|
+
} else {
|
|
72
|
+
throw strOrErr;
|
|
73
|
+
}
|
|
64
74
|
}
|
|
65
75
|
}
|
|
66
76
|
/**
|
package/lib/basics.d.ts
CHANGED
|
@@ -3,8 +3,32 @@ import { Decoder, Scalar } from '../Decoder';
|
|
|
3
3
|
export const null_: Decoder<null>;
|
|
4
4
|
export const undefined_: Decoder<undefined>;
|
|
5
5
|
export function optional<T>(decoder: Decoder<T>): Decoder<T | undefined>;
|
|
6
|
+
export function optional<T, V extends Scalar>(
|
|
7
|
+
decoder: Decoder<T>,
|
|
8
|
+
defaultValue: V,
|
|
9
|
+
): Decoder<NonNullable<T> | V>;
|
|
10
|
+
export function optional<T, V>(
|
|
11
|
+
decoder: Decoder<T>,
|
|
12
|
+
defaultValue: V,
|
|
13
|
+
): Decoder<NonNullable<T> | V>;
|
|
6
14
|
export function nullable<T>(decoder: Decoder<T>): Decoder<T | null>;
|
|
15
|
+
export function nullable<T, V extends Scalar>(
|
|
16
|
+
decoder: Decoder<T>,
|
|
17
|
+
defaultValue: V,
|
|
18
|
+
): Decoder<NonNullable<T> | V>;
|
|
19
|
+
export function nullable<T, V>(
|
|
20
|
+
decoder: Decoder<T>,
|
|
21
|
+
defaultValue: V,
|
|
22
|
+
): Decoder<NonNullable<T> | V>;
|
|
7
23
|
export function maybe<T>(decoder: Decoder<T>): Decoder<T | null | undefined>;
|
|
24
|
+
export function maybe<T, V extends Scalar>(
|
|
25
|
+
decoder: Decoder<T>,
|
|
26
|
+
defaultValue: V,
|
|
27
|
+
): Decoder<NonNullable<T> | V>;
|
|
28
|
+
export function maybe<T, V>(
|
|
29
|
+
decoder: Decoder<T>,
|
|
30
|
+
defaultValue: V,
|
|
31
|
+
): Decoder<NonNullable<T> | V>;
|
|
8
32
|
export function constant<T extends Scalar>(value: T): Decoder<T>;
|
|
9
33
|
export function always<T extends Scalar>(value: T): Decoder<T>;
|
|
10
34
|
export function always<T>(value: T): Decoder<T>;
|
package/lib/basics.js
CHANGED
|
@@ -3,12 +3,7 @@
|
|
|
3
3
|
exports.__esModule = true;
|
|
4
4
|
exports.always = always;
|
|
5
5
|
exports.constant = constant;
|
|
6
|
-
exports.hardcoded = void 0;
|
|
7
|
-
exports.maybe = maybe;
|
|
8
|
-
exports.null_ = exports.mixed = void 0;
|
|
9
|
-
exports.nullable = nullable;
|
|
10
|
-
exports.optional = optional;
|
|
11
|
-
exports.unknown = exports.undefined_ = void 0;
|
|
6
|
+
exports.unknown = exports.undefined_ = exports.optional = exports.nullable = exports.null_ = exports.mixed = exports.maybe = exports.hardcoded = void 0;
|
|
12
7
|
|
|
13
8
|
var _Decoder = require("../Decoder");
|
|
14
9
|
|
|
@@ -28,40 +23,70 @@ exports.null_ = null_;
|
|
|
28
23
|
var undefined_ = (0, _Decoder.define)(function (blob, ok, err) {
|
|
29
24
|
return blob === undefined ? ok(blob) : err('Must be undefined');
|
|
30
25
|
});
|
|
31
|
-
/**
|
|
32
|
-
* Accepts whatever the given decoder accepts, or `undefined`.
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
26
|
exports.undefined_ = undefined_;
|
|
27
|
+
var undefined_or_null = (0, _Decoder.define)(function (blob, ok, err) {
|
|
28
|
+
return blob === undefined || blob === null ? ok(blob) : // Combine error message into a single line for readability
|
|
29
|
+
err('Must be undefined or null');
|
|
30
|
+
});
|
|
36
31
|
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Accepts whatever the given decoder accepts, or `null`, or `undefined`.
|
|
34
|
+
*/
|
|
35
|
+
function _maybeish(emptyCase) {
|
|
36
|
+
function _inner(decoder
|
|
37
|
+
/* defaultValue */
|
|
38
|
+
) {
|
|
39
|
+
var _arguments = arguments;
|
|
40
|
+
var rv = (0, _unions.either)(emptyCase, decoder);
|
|
41
|
+
return (// If a default value is provided...
|
|
42
|
+
arguments.length >= 2 ? // ...then return the default value
|
|
43
|
+
rv.transform(function (value) {
|
|
44
|
+
return value != null ? value : _arguments[1];
|
|
45
|
+
}) : // Otherwise the "normal" empty case
|
|
46
|
+
rv
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return _inner;
|
|
39
51
|
}
|
|
40
52
|
/**
|
|
41
53
|
* Accepts whatever the given decoder accepts, or `null`.
|
|
54
|
+
*
|
|
55
|
+
* If a default value is explicitly provided, return that instead in the `null`
|
|
56
|
+
* case.
|
|
42
57
|
*/
|
|
43
58
|
|
|
44
59
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
60
|
+
var nullable = _maybeish(null_);
|
|
61
|
+
/**
|
|
62
|
+
* Accepts whatever the given decoder accepts, or `undefined`.
|
|
63
|
+
*
|
|
64
|
+
* If a default value is explicitly provided, return that instead in the
|
|
65
|
+
* `undefined` case.
|
|
66
|
+
*/
|
|
48
67
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
68
|
+
|
|
69
|
+
exports.nullable = nullable;
|
|
70
|
+
|
|
71
|
+
var optional = _maybeish(undefined_);
|
|
53
72
|
/**
|
|
54
73
|
* Accepts whatever the given decoder accepts, or `null`, or `undefined`.
|
|
74
|
+
*
|
|
75
|
+
* If a default value is explicitly provided, return that instead in the
|
|
76
|
+
* `null`/`undefined` case.
|
|
55
77
|
*/
|
|
56
78
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
79
|
+
|
|
80
|
+
exports.optional = optional;
|
|
81
|
+
|
|
82
|
+
var maybe = _maybeish(undefined_or_null);
|
|
60
83
|
/**
|
|
61
84
|
* Accepts only the given constant value.
|
|
62
85
|
*/
|
|
63
86
|
|
|
64
87
|
|
|
88
|
+
exports.maybe = maybe;
|
|
89
|
+
|
|
65
90
|
function constant(value) {
|
|
66
91
|
return (0, _Decoder.define)(function (blob, ok, err) {
|
|
67
92
|
return blob === value ? ok(value) : err("Must be constant " + String(value));
|
package/lib/basics.js.flow
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { define } from '../Decoder';
|
|
4
4
|
import { either } from './unions';
|
|
5
|
+
import type { _Any } from '../_utils';
|
|
5
6
|
import type { Decoder, Scalar } from '../Decoder';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -18,33 +19,60 @@ export const undefined_: Decoder<void> = define((blob, ok, err) =>
|
|
|
18
19
|
blob === undefined ? ok(blob) : err('Must be undefined'),
|
|
19
20
|
);
|
|
20
21
|
|
|
22
|
+
const undefined_or_null: Decoder<null | void> = define((blob, ok, err) =>
|
|
23
|
+
blob === undefined || blob === null
|
|
24
|
+
? ok(blob)
|
|
25
|
+
: // Combine error message into a single line for readability
|
|
26
|
+
err('Must be undefined or null'),
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
interface Maybeish<E> {
|
|
30
|
+
<T>(decoder: Decoder<T>): Decoder<E | T>;
|
|
31
|
+
<T, V>(decoder: Decoder<T>, defaultValue: V): Decoder<$NonMaybeType<T> | V>;
|
|
32
|
+
}
|
|
33
|
+
|
|
21
34
|
/**
|
|
22
|
-
* Accepts whatever the given decoder accepts, or `undefined`.
|
|
35
|
+
* Accepts whatever the given decoder accepts, or `null`, or `undefined`.
|
|
23
36
|
*/
|
|
24
|
-
|
|
25
|
-
|
|
37
|
+
function _maybeish<E>(emptyCase: Decoder<E>): Maybeish<E> {
|
|
38
|
+
function _inner(decoder /* defaultValue */) {
|
|
39
|
+
const rv = either(emptyCase, decoder);
|
|
40
|
+
return (
|
|
41
|
+
// If a default value is provided...
|
|
42
|
+
arguments.length >= 2
|
|
43
|
+
? // ...then return the default value
|
|
44
|
+
rv.transform((value) => value ?? arguments[1])
|
|
45
|
+
: // Otherwise the "normal" empty case
|
|
46
|
+
rv
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return (_inner: _Any);
|
|
26
51
|
}
|
|
27
52
|
|
|
28
53
|
/**
|
|
29
54
|
* Accepts whatever the given decoder accepts, or `null`.
|
|
55
|
+
*
|
|
56
|
+
* If a default value is explicitly provided, return that instead in the `null`
|
|
57
|
+
* case.
|
|
30
58
|
*/
|
|
31
|
-
export
|
|
32
|
-
return either(null_, decoder);
|
|
33
|
-
}
|
|
59
|
+
export const nullable: Maybeish<null> = _maybeish(null_);
|
|
34
60
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Accepts whatever the given decoder accepts, or `undefined`.
|
|
63
|
+
*
|
|
64
|
+
* If a default value is explicitly provided, return that instead in the
|
|
65
|
+
* `undefined` case.
|
|
66
|
+
*/
|
|
67
|
+
export const optional: Maybeish<void> = _maybeish(undefined_);
|
|
41
68
|
|
|
42
69
|
/**
|
|
43
70
|
* Accepts whatever the given decoder accepts, or `null`, or `undefined`.
|
|
71
|
+
*
|
|
72
|
+
* If a default value is explicitly provided, return that instead in the
|
|
73
|
+
* `null`/`undefined` case.
|
|
44
74
|
*/
|
|
45
|
-
export
|
|
46
|
-
return either(undefined_or_null, decoder);
|
|
47
|
-
}
|
|
75
|
+
export const maybe: Maybeish<null | void> = _maybeish(undefined_or_null);
|
|
48
76
|
|
|
49
77
|
/**
|
|
50
78
|
* Accepts only the given constant value.
|
package/lib/basics.mjs
CHANGED
|
@@ -14,31 +14,56 @@ export var null_ = define(function (blob, ok, err) {
|
|
|
14
14
|
export var undefined_ = define(function (blob, ok, err) {
|
|
15
15
|
return blob === undefined ? ok(blob) : err('Must be undefined');
|
|
16
16
|
});
|
|
17
|
+
var undefined_or_null = define(function (blob, ok, err) {
|
|
18
|
+
return blob === undefined || blob === null ? ok(blob) : // Combine error message into a single line for readability
|
|
19
|
+
err('Must be undefined or null');
|
|
20
|
+
});
|
|
21
|
+
|
|
17
22
|
/**
|
|
18
|
-
* Accepts whatever the given decoder accepts, or `undefined`.
|
|
23
|
+
* Accepts whatever the given decoder accepts, or `null`, or `undefined`.
|
|
19
24
|
*/
|
|
25
|
+
function _maybeish(emptyCase) {
|
|
26
|
+
function _inner(decoder
|
|
27
|
+
/* defaultValue */
|
|
28
|
+
) {
|
|
29
|
+
var _arguments = arguments;
|
|
30
|
+
var rv = either(emptyCase, decoder);
|
|
31
|
+
return (// If a default value is provided...
|
|
32
|
+
arguments.length >= 2 ? // ...then return the default value
|
|
33
|
+
rv.transform(function (value) {
|
|
34
|
+
return value != null ? value : _arguments[1];
|
|
35
|
+
}) : // Otherwise the "normal" empty case
|
|
36
|
+
rv
|
|
37
|
+
);
|
|
38
|
+
}
|
|
20
39
|
|
|
21
|
-
|
|
22
|
-
return either(undefined_, decoder);
|
|
40
|
+
return _inner;
|
|
23
41
|
}
|
|
24
42
|
/**
|
|
25
43
|
* Accepts whatever the given decoder accepts, or `null`.
|
|
44
|
+
*
|
|
45
|
+
* If a default value is explicitly provided, return that instead in the `null`
|
|
46
|
+
* case.
|
|
26
47
|
*/
|
|
27
48
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
49
|
+
|
|
50
|
+
export var nullable = _maybeish(null_);
|
|
51
|
+
/**
|
|
52
|
+
* Accepts whatever the given decoder accepts, or `undefined`.
|
|
53
|
+
*
|
|
54
|
+
* If a default value is explicitly provided, return that instead in the
|
|
55
|
+
* `undefined` case.
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
export var optional = _maybeish(undefined_);
|
|
35
59
|
/**
|
|
36
60
|
* Accepts whatever the given decoder accepts, or `null`, or `undefined`.
|
|
61
|
+
*
|
|
62
|
+
* If a default value is explicitly provided, return that instead in the
|
|
63
|
+
* `null`/`undefined` case.
|
|
37
64
|
*/
|
|
38
65
|
|
|
39
|
-
export
|
|
40
|
-
return either(undefined_or_null, decoder);
|
|
41
|
-
}
|
|
66
|
+
export var maybe = _maybeish(undefined_or_null);
|
|
42
67
|
/**
|
|
43
68
|
* Accepts only the given constant value.
|
|
44
69
|
*/
|
package/lib/objects.js.flow
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import { annotateObject, merge, updateText } from '../annotate';
|
|
4
4
|
import { define } from '../Decoder';
|
|
5
|
-
import type { _Any } from '../_utils';
|
|
6
5
|
import type { Annotation } from '../annotate';
|
|
6
|
+
import type { _Any as AnyDecoder } from '../_utils';
|
|
7
7
|
import type { Decoder, DecodeResult } from '../Decoder';
|
|
8
8
|
|
|
9
9
|
function subtract(xs: Set<string>, ys: Set<string>): Set<string> {
|
|
@@ -52,7 +52,7 @@ export const pojo: Decoder<{| [string]: mixed |}> = define((blob, ok, err) =>
|
|
|
52
52
|
* Accepts objects with fields matching the given decoders. Extra fields that
|
|
53
53
|
* exist on the input object are ignored and will not be returned.
|
|
54
54
|
*/
|
|
55
|
-
export function object<O: { +[field: string]:
|
|
55
|
+
export function object<O: { +[field: string]: AnyDecoder, ... }>(
|
|
56
56
|
decodersByKey: O,
|
|
57
57
|
): Decoder<$ObjMap<O, <T>(Decoder<T>) => T>> {
|
|
58
58
|
// Compute this set at decoder definition time
|
|
@@ -134,7 +134,7 @@ export function object<O: { +[field: string]: Decoder<_Any>, ... }>(
|
|
|
134
134
|
* Like `object()`, but will reject inputs that contain extra fields that are
|
|
135
135
|
* not specified explicitly.
|
|
136
136
|
*/
|
|
137
|
-
export function exact<O: { +[field: string]:
|
|
137
|
+
export function exact<O: { +[field: string]: AnyDecoder, ... }>(
|
|
138
138
|
decodersByKey: O,
|
|
139
139
|
): Decoder<$ObjMap<$Exact<O>, <T>(Decoder<T>) => T>> {
|
|
140
140
|
// Compute this set at decoder definition time
|
|
@@ -160,7 +160,7 @@ export function exact<O: { +[field: string]: Decoder<_Any>, ... }>(
|
|
|
160
160
|
* Like `object()`, but will pass through any extra fields on the input object
|
|
161
161
|
* unvalidated that will thus be of `unknown` type statically.
|
|
162
162
|
*/
|
|
163
|
-
export function inexact<O: { +[field: string]:
|
|
163
|
+
export function inexact<O: { +[field: string]: AnyDecoder }>(
|
|
164
164
|
decodersByKey: O,
|
|
165
165
|
): Decoder<$ObjMap<O, <T>(Decoder<T>) => T> & { +[string]: mixed }> {
|
|
166
166
|
return pojo.then((plainObj) => {
|