decoders 2.0.0-beta1 → 2.0.0-beta10

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.
Files changed (160) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/Decoder.d.ts +27 -0
  3. package/Decoder.js +199 -0
  4. package/Decoder.js.flow +224 -0
  5. package/Decoder.mjs +192 -0
  6. package/NotSupportedTSVersion.d.ts +1 -0
  7. package/README.md +105 -961
  8. package/_utils.d.ts +9 -0
  9. package/{cjs/_utils.js → _utils.js} +12 -18
  10. package/{cjs/_utils.js.flow → _utils.js.flow} +15 -19
  11. package/{es/_utils.js → _utils.mjs} +11 -15
  12. package/{ts/annotate.d.ts → annotate.d.ts} +25 -21
  13. package/{cjs/annotate.js → annotate.js} +0 -0
  14. package/{cjs/annotate.js.flow → annotate.js.flow} +0 -0
  15. package/{es/annotate.js → annotate.mjs} +0 -0
  16. package/format.d.ts +4 -0
  17. package/{cjs/format/inline.js → format.js} +7 -2
  18. package/{cjs/format/inline.js.flow → format.js.flow} +7 -3
  19. package/{es/format/inline.js → format.mjs} +5 -2
  20. package/index.d.ts +40 -0
  21. package/index.js +90 -0
  22. package/index.js.flow +44 -0
  23. package/index.mjs +11 -0
  24. package/{ts → lib}/_helpers.d.ts +0 -0
  25. package/lib/arrays.d.ts +37 -0
  26. package/lib/arrays.js +138 -0
  27. package/lib/arrays.js.flow +138 -0
  28. package/lib/arrays.mjs +123 -0
  29. package/lib/basics.d.ts +14 -0
  30. package/lib/basics.js +109 -0
  31. package/lib/basics.js.flow +85 -0
  32. package/lib/basics.mjs +85 -0
  33. package/{ts/boolean.d.ts → lib/booleans.d.ts} +1 -1
  34. package/lib/booleans.js +35 -0
  35. package/lib/booleans.js.flow +22 -0
  36. package/lib/booleans.mjs +25 -0
  37. package/{ts/date.d.ts → lib/dates.d.ts} +1 -1
  38. package/lib/dates.js +44 -0
  39. package/lib/dates.js.flow +40 -0
  40. package/lib/dates.mjs +34 -0
  41. package/{ts → lib}/json.d.ts +1 -1
  42. package/lib/json.js +55 -0
  43. package/lib/json.js.flow +50 -0
  44. package/lib/json.mjs +40 -0
  45. package/{ts/number.d.ts → lib/numbers.d.ts} +2 -1
  46. package/lib/numbers.js +52 -0
  47. package/lib/numbers.js.flow +49 -0
  48. package/lib/numbers.mjs +42 -0
  49. package/{ts/object.d.ts → lib/objects.d.ts} +9 -4
  50. package/lib/objects.js +240 -0
  51. package/lib/objects.js.flow +246 -0
  52. package/lib/objects.mjs +223 -0
  53. package/lib/strings.d.ts +13 -0
  54. package/lib/strings.js +101 -0
  55. package/lib/strings.js.flow +90 -0
  56. package/lib/strings.mjs +82 -0
  57. package/lib/unions.d.ts +78 -0
  58. package/lib/unions.js +161 -0
  59. package/lib/unions.js.flow +158 -0
  60. package/lib/unions.mjs +145 -0
  61. package/lib/utilities.d.ts +10 -0
  62. package/lib/utilities.js +94 -0
  63. package/lib/utilities.js.flow +84 -0
  64. package/lib/utilities.mjs +79 -0
  65. package/package.json +79 -29
  66. package/result.d.ts +16 -0
  67. package/result.js +34 -0
  68. package/result.js.flow +26 -0
  69. package/result.mjs +27 -0
  70. package/cjs/_guard.js +0 -26
  71. package/cjs/_guard.js.flow +0 -20
  72. package/cjs/_types.js +0 -1
  73. package/cjs/_types.js.flow +0 -20
  74. package/cjs/format/index.js +0 -12
  75. package/cjs/format/index.js.flow +0 -4
  76. package/cjs/format/short.js +0 -10
  77. package/cjs/format/short.js.flow +0 -8
  78. package/cjs/index.js +0 -120
  79. package/cjs/index.js.flow +0 -63
  80. package/cjs/result.js +0 -172
  81. package/cjs/result.js.flow +0 -166
  82. package/cjs/stdlib/array.js +0 -108
  83. package/cjs/stdlib/array.js.flow +0 -103
  84. package/cjs/stdlib/boolean.js +0 -44
  85. package/cjs/stdlib/boolean.js.flow +0 -29
  86. package/cjs/stdlib/composition.js +0 -56
  87. package/cjs/stdlib/composition.js.flow +0 -43
  88. package/cjs/stdlib/constants.js +0 -69
  89. package/cjs/stdlib/constants.js.flow +0 -46
  90. package/cjs/stdlib/date.js +0 -46
  91. package/cjs/stdlib/date.js.flow +0 -40
  92. package/cjs/stdlib/describe.js +0 -26
  93. package/cjs/stdlib/describe.js.flow +0 -17
  94. package/cjs/stdlib/dispatch.js +0 -62
  95. package/cjs/stdlib/dispatch.js.flow +0 -58
  96. package/cjs/stdlib/either.js +0 -117
  97. package/cjs/stdlib/either.js.flow +0 -151
  98. package/cjs/stdlib/fail.js +0 -21
  99. package/cjs/stdlib/fail.js.flow +0 -12
  100. package/cjs/stdlib/instanceOf.js +0 -19
  101. package/cjs/stdlib/instanceOf.js.flow +0 -20
  102. package/cjs/stdlib/json.js +0 -31
  103. package/cjs/stdlib/json.js.flow +0 -28
  104. package/cjs/stdlib/lazy.js +0 -16
  105. package/cjs/stdlib/lazy.js.flow +0 -15
  106. package/cjs/stdlib/mapping.js +0 -67
  107. package/cjs/stdlib/mapping.js.flow +0 -54
  108. package/cjs/stdlib/number.js +0 -40
  109. package/cjs/stdlib/number.js.flow +0 -34
  110. package/cjs/stdlib/object.js +0 -194
  111. package/cjs/stdlib/object.js.flow +0 -203
  112. package/cjs/stdlib/optional.js +0 -54
  113. package/cjs/stdlib/optional.js.flow +0 -41
  114. package/cjs/stdlib/string.js +0 -98
  115. package/cjs/stdlib/string.js.flow +0 -82
  116. package/cjs/stdlib/tuple.js +0 -173
  117. package/cjs/stdlib/tuple.js.flow +0 -220
  118. package/es/_guard.js +0 -15
  119. package/es/_types.js +0 -0
  120. package/es/format/index.js +0 -2
  121. package/es/format/short.js +0 -4
  122. package/es/index.js +0 -37
  123. package/es/result.js +0 -139
  124. package/es/stdlib/array.js +0 -91
  125. package/es/stdlib/boolean.js +0 -28
  126. package/es/stdlib/composition.js +0 -42
  127. package/es/stdlib/constants.js +0 -46
  128. package/es/stdlib/date.js +0 -28
  129. package/es/stdlib/describe.js +0 -16
  130. package/es/stdlib/dispatch.js +0 -51
  131. package/es/stdlib/either.js +0 -90
  132. package/es/stdlib/fail.js +0 -11
  133. package/es/stdlib/instanceOf.js +0 -8
  134. package/es/stdlib/json.js +0 -15
  135. package/es/stdlib/lazy.js +0 -11
  136. package/es/stdlib/mapping.js +0 -54
  137. package/es/stdlib/number.js +0 -25
  138. package/es/stdlib/object.js +0 -175
  139. package/es/stdlib/optional.js +0 -38
  140. package/es/stdlib/string.js +0 -76
  141. package/es/stdlib/tuple.js +0 -155
  142. package/ts/_guard.d.ts +0 -7
  143. package/ts/_types.d.ts +0 -16
  144. package/ts/_utils.d.ts +0 -13
  145. package/ts/array.d.ts +0 -5
  146. package/ts/constants.d.ts +0 -11
  147. package/ts/describe.d.ts +0 -3
  148. package/ts/dispatch.d.ts +0 -8
  149. package/ts/either.d.ts +0 -61
  150. package/ts/fail.d.ts +0 -3
  151. package/ts/index.d.ts +0 -42
  152. package/ts/inline.d.ts +0 -3
  153. package/ts/instanceOf.d.ts +0 -3
  154. package/ts/lazy.d.ts +0 -3
  155. package/ts/mapping.d.ts +0 -4
  156. package/ts/optional.d.ts +0 -5
  157. package/ts/result.d.ts +0 -39
  158. package/ts/short.d.ts +0 -3
  159. package/ts/string.d.ts +0 -7
  160. package/ts/tuple.d.ts +0 -30
package/lib/unions.js ADDED
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.either = exports.dispatch = void 0;
5
+ exports.oneOf = oneOf;
6
+ exports.taggedUnion = taggedUnion;
7
+
8
+ var _Decoder = require("../Decoder");
9
+
10
+ var _utils = require("../_utils");
11
+
12
+ var _objects = require("./objects");
13
+
14
+ var _utilities = require("./utilities");
15
+
16
+ var EITHER_PREFIX = 'Either:\n';
17
+ /**
18
+ * Indents and adds a dash in front of this (potentially multiline) string.
19
+ */
20
+
21
+ function itemize(s) {
22
+ return '-' + (0, _utils.indent)(s).substring(1);
23
+ }
24
+ /**
25
+ * Nests another error as an item under a new-to-be-created "Either error". If
26
+ * the given subitem already is an "Either error" of itself, don't indent, but
27
+ * just "inject" its items at the same error level, for nicely flattened either
28
+ * expressions.
29
+ *
30
+ * Avoids:
31
+ *
32
+ * Either:
33
+ * - Either:
34
+ * - Must be P
35
+ * - Either:
36
+ * - Must be Q
37
+ * - Must be R
38
+ * - Must be S
39
+ *
40
+ * And "flattens" these to:
41
+ *
42
+ * Either:
43
+ * - Must be P
44
+ * - Must be Q
45
+ * - Must be R
46
+ * - Must be S
47
+ *
48
+ */
49
+
50
+
51
+ function nest(errText) {
52
+ return errText.startsWith(EITHER_PREFIX) ? errText.substr(EITHER_PREFIX.length) : itemize(errText);
53
+ } // prettier-ignore
54
+
55
+
56
+ function _either() {
57
+ for (var _len = arguments.length, decoders = new Array(_len), _key = 0; _key < _len; _key++) {
58
+ decoders[_key] = arguments[_key];
59
+ }
60
+
61
+ if (decoders.length === 0) {
62
+ throw new Error('Pass at least one decoder to either()');
63
+ }
64
+
65
+ return (0, _Decoder.define)(function (blob, _, err) {
66
+ // Collect errors here along the way
67
+ var errors = [];
68
+
69
+ for (var _i = 0; _i < decoders.length; _i++) {
70
+ var result = decoders[_i].decode(blob);
71
+
72
+ if (result.ok) {
73
+ return result;
74
+ } else {
75
+ errors.push(result.error);
76
+ }
77
+ } // Decoding all alternatives failed, return the combined error message
78
+
79
+
80
+ var text = EITHER_PREFIX + errors.map(function (err) {
81
+ return nest((0, _utils.summarize)(err).join('\n'));
82
+ }).join('\n');
83
+ return err(text);
84
+ });
85
+ }
86
+ /**
87
+ * Accepts values accepted by any of the given decoders.
88
+ *
89
+ * The decoders are tried on the input one by one, in the given order. The
90
+ * first one that accepts the input "wins". If all decoders reject the input,
91
+ * the input gets rejected.
92
+ */
93
+
94
+
95
+ var either = _either;
96
+ /**
97
+ * Accepts any value that is strictly-equal (using ===) to one of the specified
98
+ * values.
99
+ */
100
+
101
+ exports.either = either;
102
+
103
+ function oneOf(constants) {
104
+ return (0, _Decoder.define)(function (blob, ok, err) {
105
+ var winner = constants.find(function (c) {
106
+ return c === blob;
107
+ });
108
+
109
+ if (winner !== undefined) {
110
+ return ok(winner);
111
+ }
112
+
113
+ return err("Must be one of " + constants.map(function (value) {
114
+ return JSON.stringify(value);
115
+ }).join(', '));
116
+ });
117
+ }
118
+ /**
119
+ * If you are decoding tagged unions you may want to use the `taggedUnion()`
120
+ * decoder instead of the general purpose `either()` decoder to get better
121
+ * error messages and better performance.
122
+ *
123
+ * This decoder is optimized for [tagged
124
+ * unions](https://en.wikipedia.org/wiki/Tagged_union), i.e. a union of
125
+ * objects where one field is used as the discriminator.
126
+ *
127
+ * const A = object({ tag: constant('A'), foo: string });
128
+ * const B = object({ tag: constant('B'), bar: number });
129
+ *
130
+ * const AorB = taggedUnion('tag', { A, B });
131
+ * // ^^^
132
+ *
133
+ * Decoding now works in two steps:
134
+ *
135
+ * 1. Look at the `'tag'` field in the incoming object (this is the field
136
+ * that decides which decoder will be used)
137
+ * 2. If the value is `'A'`, then decoder `A` will be used. If it's `'B'`, then
138
+ * decoder `B` will be used. Otherwise, this will fail.
139
+ *
140
+ * This is effectively equivalent to `either(A, B)`, but will provide better
141
+ * error messages and is more performant at runtime because it doesn't have to
142
+ * try all decoders one by one.
143
+ */
144
+
145
+
146
+ function taggedUnion(field, mapping) {
147
+ var _object;
148
+
149
+ var base = (0, _objects.object)((_object = {}, _object[field] = (0, _utilities.prep)(String, oneOf(Object.keys(mapping))), _object)).transform(function (o) {
150
+ return o[field];
151
+ });
152
+ return base.peek_UNSTABLE(function (_ref) {
153
+ var blob = _ref[0],
154
+ key = _ref[1];
155
+ var decoder = mapping[key];
156
+ return decoder.decode(blob);
157
+ });
158
+ }
159
+
160
+ var dispatch = taggedUnion;
161
+ exports.dispatch = dispatch;
@@ -0,0 +1,158 @@
1
+ // @flow strict
2
+
3
+ import { define } from '../Decoder';
4
+ import { indent, summarize } from '../_utils';
5
+ import { object } from './objects';
6
+ import { prep } from './utilities';
7
+ import type { _Any } from '../_utils';
8
+ import type { Decoder, DecodeResult, Scalar } from '../Decoder';
9
+
10
+ const EITHER_PREFIX = 'Either:\n';
11
+
12
+ /**
13
+ * Indents and adds a dash in front of this (potentially multiline) string.
14
+ */
15
+ function itemize(s: string): string {
16
+ return '-' + indent(s).substring(1);
17
+ }
18
+
19
+ /**
20
+ * Nests another error as an item under a new-to-be-created "Either error". If
21
+ * the given subitem already is an "Either error" of itself, don't indent, but
22
+ * just "inject" its items at the same error level, for nicely flattened either
23
+ * expressions.
24
+ *
25
+ * Avoids:
26
+ *
27
+ * Either:
28
+ * - Either:
29
+ * - Must be P
30
+ * - Either:
31
+ * - Must be Q
32
+ * - Must be R
33
+ * - Must be S
34
+ *
35
+ * And "flattens" these to:
36
+ *
37
+ * Either:
38
+ * - Must be P
39
+ * - Must be Q
40
+ * - Must be R
41
+ * - Must be S
42
+ *
43
+ */
44
+ function nest(errText: string): string {
45
+ return errText.startsWith(EITHER_PREFIX)
46
+ ? errText.substr(EITHER_PREFIX.length)
47
+ : itemize(errText);
48
+ }
49
+
50
+ // prettier-ignore
51
+ interface EitherDecoderSignatures {
52
+ <A>(a: Decoder<A>): Decoder<A>;
53
+ <A, B>(a: Decoder<A>, b: Decoder<B>): Decoder<A | B>;
54
+ <A, B, C>(a: Decoder<A>, b: Decoder<B>, c: Decoder<C>): Decoder<A | B | C>;
55
+ <A, B, C, D>(a: Decoder<A>, b: Decoder<B>, c: Decoder<C>, d: Decoder<D>): Decoder<A | B | C | D>;
56
+ <A, B, C, D, E>(a: Decoder<A>, b: Decoder<B>, c: Decoder<C>, d: Decoder<D>, e: Decoder<E>): Decoder<A | B | C | D | E>;
57
+ <A, B, C, D, E, F>(a: Decoder<A>, b: Decoder<B>, c: Decoder<C>, d: Decoder<D>, e: Decoder<E>, f: Decoder<F>): Decoder<A | B | C | D | E | F>;
58
+ <A, B, C, D, E, F, G>(a: Decoder<A>, b: Decoder<B>, c: Decoder<C>, d: Decoder<D>, e: Decoder<E>, f: Decoder<F>, g: Decoder<G>): Decoder<A | B | C | D | E | F | G>;
59
+ <A, B, C, D, E, F, G, H>(a: Decoder<A>, b: Decoder<B>, c: Decoder<C>, d: Decoder<D>, e: Decoder<E>, f: Decoder<F>, g: Decoder<G>, h: Decoder<H>): Decoder<A | B | C | D | E | F | G | H>;
60
+ <A, B, C, D, E, F, G, H, I>(a: Decoder<A>, b: Decoder<B>, c: Decoder<C>, d: Decoder<D>, e: Decoder<E>, f: Decoder<F>, g: Decoder<G>, h: Decoder<H>, i: Decoder<I>): Decoder<A | B | C | D | E | F | G | H | I>;
61
+ }
62
+
63
+ function _either(...decoders: $ReadOnlyArray<Decoder<mixed>>): Decoder<mixed> {
64
+ if (decoders.length === 0) {
65
+ throw new Error('Pass at least one decoder to either()');
66
+ }
67
+
68
+ return define((blob, _, err) => {
69
+ // Collect errors here along the way
70
+ const errors = [];
71
+
72
+ for (let i = 0; i < decoders.length; i++) {
73
+ const result: DecodeResult<mixed> = decoders[i].decode(blob);
74
+ if (result.ok) {
75
+ return result;
76
+ } else {
77
+ errors.push(result.error);
78
+ }
79
+ }
80
+
81
+ // Decoding all alternatives failed, return the combined error message
82
+ const text =
83
+ EITHER_PREFIX +
84
+ errors.map((err) => nest(summarize(err).join('\n'))).join('\n');
85
+ return err(text);
86
+ });
87
+ }
88
+
89
+ /**
90
+ * Accepts values accepted by any of the given decoders.
91
+ *
92
+ * The decoders are tried on the input one by one, in the given order. The
93
+ * first one that accepts the input "wins". If all decoders reject the input,
94
+ * the input gets rejected.
95
+ */
96
+ export const either: EitherDecoderSignatures = (_either: _Any);
97
+
98
+ /**
99
+ * Accepts any value that is strictly-equal (using ===) to one of the specified
100
+ * values.
101
+ */
102
+ export function oneOf<T: Scalar>(constants: $ReadOnlyArray<T>): Decoder<T> {
103
+ return define((blob, ok, err) => {
104
+ const winner = constants.find((c) => c === blob);
105
+ if (winner !== undefined) {
106
+ return ok(winner);
107
+ }
108
+ return err(
109
+ `Must be one of ${constants
110
+ .map((value) => JSON.stringify(value))
111
+ .join(', ')}`,
112
+ );
113
+ });
114
+ }
115
+
116
+ /**
117
+ * If you are decoding tagged unions you may want to use the `taggedUnion()`
118
+ * decoder instead of the general purpose `either()` decoder to get better
119
+ * error messages and better performance.
120
+ *
121
+ * This decoder is optimized for [tagged
122
+ * unions](https://en.wikipedia.org/wiki/Tagged_union), i.e. a union of
123
+ * objects where one field is used as the discriminator.
124
+ *
125
+ * const A = object({ tag: constant('A'), foo: string });
126
+ * const B = object({ tag: constant('B'), bar: number });
127
+ *
128
+ * const AorB = taggedUnion('tag', { A, B });
129
+ * // ^^^
130
+ *
131
+ * Decoding now works in two steps:
132
+ *
133
+ * 1. Look at the `'tag'` field in the incoming object (this is the field
134
+ * that decides which decoder will be used)
135
+ * 2. If the value is `'A'`, then decoder `A` will be used. If it's `'B'`, then
136
+ * decoder `B` will be used. Otherwise, this will fail.
137
+ *
138
+ * This is effectively equivalent to `either(A, B)`, but will provide better
139
+ * error messages and is more performant at runtime because it doesn't have to
140
+ * try all decoders one by one.
141
+ */
142
+ export function taggedUnion<O: { +[field: string]: Decoder<_Any>, ... }>(
143
+ field: string,
144
+ mapping: O,
145
+ ): Decoder<$Values<$ObjMap<O, <T>(Decoder<T>) => T>>> {
146
+ const base: Decoder<string> = object({
147
+ [field]: prep(String, oneOf(Object.keys(mapping))),
148
+ }).transform((o) => o[field]);
149
+ return base.peek_UNSTABLE(([blob, key]) => {
150
+ const decoder = mapping[key];
151
+ return decoder.decode(blob);
152
+ });
153
+ }
154
+
155
+ export const dispatch: <O: { +[field: string]: Decoder<_Any>, ... }>(
156
+ field: string,
157
+ mapping: O,
158
+ ) => Decoder<$Values<$ObjMap<O, <T>(Decoder<T>) => T>>> = taggedUnion;
package/lib/unions.mjs ADDED
@@ -0,0 +1,145 @@
1
+ import { define } from '../Decoder.mjs';
2
+ import { indent, summarize } from '../_utils.mjs';
3
+ import { object } from './objects.mjs';
4
+ import { prep } from './utilities.mjs';
5
+ var EITHER_PREFIX = 'Either:\n';
6
+ /**
7
+ * Indents and adds a dash in front of this (potentially multiline) string.
8
+ */
9
+
10
+ function itemize(s) {
11
+ return '-' + indent(s).substring(1);
12
+ }
13
+ /**
14
+ * Nests another error as an item under a new-to-be-created "Either error". If
15
+ * the given subitem already is an "Either error" of itself, don't indent, but
16
+ * just "inject" its items at the same error level, for nicely flattened either
17
+ * expressions.
18
+ *
19
+ * Avoids:
20
+ *
21
+ * Either:
22
+ * - Either:
23
+ * - Must be P
24
+ * - Either:
25
+ * - Must be Q
26
+ * - Must be R
27
+ * - Must be S
28
+ *
29
+ * And "flattens" these to:
30
+ *
31
+ * Either:
32
+ * - Must be P
33
+ * - Must be Q
34
+ * - Must be R
35
+ * - Must be S
36
+ *
37
+ */
38
+
39
+
40
+ function nest(errText) {
41
+ return errText.startsWith(EITHER_PREFIX) ? errText.substr(EITHER_PREFIX.length) : itemize(errText);
42
+ } // prettier-ignore
43
+
44
+
45
+ function _either() {
46
+ for (var _len = arguments.length, decoders = new Array(_len), _key = 0; _key < _len; _key++) {
47
+ decoders[_key] = arguments[_key];
48
+ }
49
+
50
+ if (decoders.length === 0) {
51
+ throw new Error('Pass at least one decoder to either()');
52
+ }
53
+
54
+ return define(function (blob, _, err) {
55
+ // Collect errors here along the way
56
+ var errors = [];
57
+
58
+ for (var _i = 0; _i < decoders.length; _i++) {
59
+ var result = decoders[_i].decode(blob);
60
+
61
+ if (result.ok) {
62
+ return result;
63
+ } else {
64
+ errors.push(result.error);
65
+ }
66
+ } // Decoding all alternatives failed, return the combined error message
67
+
68
+
69
+ var text = EITHER_PREFIX + errors.map(function (err) {
70
+ return nest(summarize(err).join('\n'));
71
+ }).join('\n');
72
+ return err(text);
73
+ });
74
+ }
75
+ /**
76
+ * Accepts values accepted by any of the given decoders.
77
+ *
78
+ * The decoders are tried on the input one by one, in the given order. The
79
+ * first one that accepts the input "wins". If all decoders reject the input,
80
+ * the input gets rejected.
81
+ */
82
+
83
+
84
+ export var either = _either;
85
+ /**
86
+ * Accepts any value that is strictly-equal (using ===) to one of the specified
87
+ * values.
88
+ */
89
+
90
+ export function oneOf(constants) {
91
+ return define(function (blob, ok, err) {
92
+ var winner = constants.find(function (c) {
93
+ return c === blob;
94
+ });
95
+
96
+ if (winner !== undefined) {
97
+ return ok(winner);
98
+ }
99
+
100
+ return err("Must be one of " + constants.map(function (value) {
101
+ return JSON.stringify(value);
102
+ }).join(', '));
103
+ });
104
+ }
105
+ /**
106
+ * If you are decoding tagged unions you may want to use the `taggedUnion()`
107
+ * decoder instead of the general purpose `either()` decoder to get better
108
+ * error messages and better performance.
109
+ *
110
+ * This decoder is optimized for [tagged
111
+ * unions](https://en.wikipedia.org/wiki/Tagged_union), i.e. a union of
112
+ * objects where one field is used as the discriminator.
113
+ *
114
+ * const A = object({ tag: constant('A'), foo: string });
115
+ * const B = object({ tag: constant('B'), bar: number });
116
+ *
117
+ * const AorB = taggedUnion('tag', { A, B });
118
+ * // ^^^
119
+ *
120
+ * Decoding now works in two steps:
121
+ *
122
+ * 1. Look at the `'tag'` field in the incoming object (this is the field
123
+ * that decides which decoder will be used)
124
+ * 2. If the value is `'A'`, then decoder `A` will be used. If it's `'B'`, then
125
+ * decoder `B` will be used. Otherwise, this will fail.
126
+ *
127
+ * This is effectively equivalent to `either(A, B)`, but will provide better
128
+ * error messages and is more performant at runtime because it doesn't have to
129
+ * try all decoders one by one.
130
+ */
131
+
132
+ export function taggedUnion(field, mapping) {
133
+ var _object;
134
+
135
+ var base = object((_object = {}, _object[field] = prep(String, oneOf(Object.keys(mapping))), _object)).transform(function (o) {
136
+ return o[field];
137
+ });
138
+ return base.peek_UNSTABLE(function (_ref) {
139
+ var blob = _ref[0],
140
+ key = _ref[1];
141
+ var decoder = mapping[key];
142
+ return decoder.decode(blob);
143
+ });
144
+ }
145
+ export var dispatch = taggedUnion;
@@ -0,0 +1,10 @@
1
+ import { Decoder } from '../Decoder';
2
+
3
+ export function instanceOf<T>(klass: new (...args: readonly any[]) => T): Decoder<T>;
4
+ export function lazy<T>(decoderFn: () => Decoder<T>): Decoder<T>;
5
+ export function prep<T>(
6
+ mapperFn: (blob: unknown) => unknown,
7
+ decoder: Decoder<T>,
8
+ ): Decoder<T>;
9
+ export function never(msg: string): Decoder<never>;
10
+ export function fail(msg: string): Decoder<never>;
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.fail = void 0;
5
+ exports.instanceOf = instanceOf;
6
+ exports.lazy = lazy;
7
+ exports.never = never;
8
+ exports.prep = prep;
9
+
10
+ var _annotate = require("../annotate");
11
+
12
+ var _Decoder = require("../Decoder");
13
+
14
+ /**
15
+ * Accepts any value that is an ``instanceof`` the given class.
16
+ */
17
+ function instanceOf(klass) {
18
+ return (0, _Decoder.define)(function (blob, ok, err) {
19
+ return blob instanceof klass ? ok(blob) : err("Must be " + // $FlowFixMe[incompatible-use] - klass.name is fine?
20
+ klass.name + " instance");
21
+ });
22
+ }
23
+ /**
24
+ * Lazily evaluate the given decoder. This is useful to build self-referential
25
+ * types for recursive data structures.
26
+ *
27
+ * Example:
28
+ *
29
+ * ```ts
30
+ * type Tree = {
31
+ * value: string;
32
+ * children: Array<Tree>;
33
+ * // ^^^^
34
+ * // Self-reference defining a recursive type
35
+ * };
36
+ *
37
+ * const treeDecoder: Decoder<Tree> = object({
38
+ * value: string,
39
+ * children: array(lazy(() => treeDecoder)),
40
+ * // ^^^^^^^^^^^^^^^^^^^^^^^
41
+ * // Use lazy() like this to refer to the treeDecoder which is
42
+ * // getting defined here
43
+ * });
44
+ * ```
45
+ */
46
+
47
+
48
+ function lazy(decoderFn) {
49
+ return (0, _Decoder.define)(function (blob) {
50
+ return decoderFn().decode(blob);
51
+ });
52
+ }
53
+ /**
54
+ * Pre-process the data input before passing it into the decoder. This gives
55
+ * you the ability to arbitrarily customize the input on the fly before passing
56
+ * it to the decoder. Of course, the input value at that point is still of
57
+ * ``unknown`` type, so you will have to deal with that accordingly.
58
+ */
59
+
60
+
61
+ function prep(mapperFn, decoder) {
62
+ return (0, _Decoder.define)(function (originalInput, _, err) {
63
+ var blob;
64
+
65
+ try {
66
+ blob = mapperFn(originalInput);
67
+ } catch (e) {
68
+ return err((0, _annotate.annotate)(originalInput, e.message));
69
+ }
70
+
71
+ var r = decoder.decode(blob);
72
+ return r.ok ? r : err((0, _annotate.annotate)(originalInput, r.error.text)); // ^^^^^^^^^^^^^
73
+ // Annotates the _original_ input value
74
+ // (instead of echoing back blob)
75
+ });
76
+ }
77
+ /**
78
+ * Rejects all inputs, and always fails with the given error message. May be
79
+ * useful for explicitly disallowing keys, or for testing purposes.
80
+ */
81
+
82
+
83
+ function never(msg) {
84
+ return (0, _Decoder.define)(function (_, __, err) {
85
+ return err(msg);
86
+ });
87
+ }
88
+ /**
89
+ * Alias of never().
90
+ */
91
+
92
+
93
+ var fail = never;
94
+ exports.fail = fail;
@@ -0,0 +1,84 @@
1
+ // @flow strict
2
+
3
+ import { annotate } from '../annotate';
4
+ import { define } from '../Decoder';
5
+ import type { Decoder } from '../Decoder';
6
+
7
+ /**
8
+ * Accepts any value that is an ``instanceof`` the given class.
9
+ */
10
+ export function instanceOf<T>(klass: Class<T>): Decoder<T> {
11
+ return define((blob, ok, err) =>
12
+ blob instanceof klass
13
+ ? ok(blob)
14
+ : err(
15
+ `Must be ${
16
+ // $FlowFixMe[incompatible-use] - klass.name is fine?
17
+ klass.name
18
+ } instance`,
19
+ ),
20
+ );
21
+ }
22
+
23
+ /**
24
+ * Lazily evaluate the given decoder. This is useful to build self-referential
25
+ * types for recursive data structures.
26
+ *
27
+ * Example:
28
+ *
29
+ * ```ts
30
+ * type Tree = {
31
+ * value: string;
32
+ * children: Array<Tree>;
33
+ * // ^^^^
34
+ * // Self-reference defining a recursive type
35
+ * };
36
+ *
37
+ * const treeDecoder: Decoder<Tree> = object({
38
+ * value: string,
39
+ * children: array(lazy(() => treeDecoder)),
40
+ * // ^^^^^^^^^^^^^^^^^^^^^^^
41
+ * // Use lazy() like this to refer to the treeDecoder which is
42
+ * // getting defined here
43
+ * });
44
+ * ```
45
+ */
46
+ export function lazy<T>(decoderFn: () => Decoder<T>): Decoder<T> {
47
+ return define((blob) => decoderFn().decode(blob));
48
+ }
49
+
50
+ /**
51
+ * Pre-process the data input before passing it into the decoder. This gives
52
+ * you the ability to arbitrarily customize the input on the fly before passing
53
+ * it to the decoder. Of course, the input value at that point is still of
54
+ * ``unknown`` type, so you will have to deal with that accordingly.
55
+ */
56
+ export function prep<T>(mapperFn: (mixed) => mixed, decoder: Decoder<T>): Decoder<T> {
57
+ return define((originalInput, _, err) => {
58
+ let blob;
59
+ try {
60
+ blob = mapperFn(originalInput);
61
+ } catch (e) {
62
+ return err(annotate(originalInput, e.message));
63
+ }
64
+
65
+ const r = decoder.decode(blob);
66
+ return r.ok ? r : err(annotate(originalInput, r.error.text));
67
+ // ^^^^^^^^^^^^^
68
+ // Annotates the _original_ input value
69
+ // (instead of echoing back blob)
70
+ });
71
+ }
72
+
73
+ /**
74
+ * Rejects all inputs, and always fails with the given error message. May be
75
+ * useful for explicitly disallowing keys, or for testing purposes.
76
+ */
77
+ export function never(msg: string): Decoder<empty> {
78
+ return define((_, __, err) => err(msg));
79
+ }
80
+
81
+ /**
82
+ * Alias of never().
83
+ */
84
+ export const fail: (msg: string) => Decoder<empty> = never;