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.
Files changed (139) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/NotSupportedTSVersion.d.ts +1 -0
  3. package/README.md +934 -387
  4. package/_guard.d.ts +7 -0
  5. package/_guard.js +2 -6
  6. package/_guard.js.flow +3 -3
  7. package/{_esm/_guard.js → _guard.mjs} +3 -3
  8. package/_types.d.ts +13 -0
  9. package/{_esm/_types.js → _types.mjs} +0 -0
  10. package/_utils.d.ts +10 -0
  11. package/_utils.js +1 -1
  12. package/_utils.js.flow +3 -3
  13. package/{_esm/_utils.js → _utils.mjs} +1 -1
  14. package/annotate.d.ts +62 -0
  15. package/{_esm/annotate.js → annotate.mjs} +0 -0
  16. package/core/_helpers.d.ts +79 -0
  17. package/core/array.d.ts +8 -0
  18. package/core/array.js +19 -12
  19. package/core/array.js.flow +15 -11
  20. package/{_esm/core/array.js → core/array.mjs} +19 -10
  21. package/core/boolean.d.ts +5 -0
  22. package/core/boolean.js +5 -9
  23. package/core/boolean.js.flow +5 -7
  24. package/{_esm/core/boolean.js → core/boolean.mjs} +7 -7
  25. package/core/composition.d.ts +18 -0
  26. package/core/composition.js +41 -15
  27. package/core/composition.js.flow +41 -10
  28. package/core/composition.mjs +70 -0
  29. package/core/constants.d.ts +11 -0
  30. package/core/constants.js +6 -10
  31. package/core/constants.js.flow +7 -9
  32. package/{_esm/core/constants.js → core/constants.mjs} +7 -7
  33. package/core/date.d.ts +4 -0
  34. package/core/date.js +5 -9
  35. package/core/date.js.flow +4 -6
  36. package/{_esm/core/date.js → core/date.mjs} +7 -7
  37. package/core/describe.d.ts +3 -0
  38. package/core/describe.js +2 -6
  39. package/core/describe.js.flow +2 -2
  40. package/{_esm/core/describe.js → core/describe.mjs} +3 -3
  41. package/core/dispatch.d.ts +8 -0
  42. package/core/dispatch.js +11 -13
  43. package/core/dispatch.js.flow +13 -12
  44. package/{_esm/core/dispatch.js → core/dispatch.mjs} +12 -11
  45. package/core/either.d.ts +66 -0
  46. package/core/either.js +34 -50
  47. package/core/either.js.flow +40 -86
  48. package/core/either.mjs +90 -0
  49. package/core/fail.d.ts +3 -0
  50. package/core/fail.js +2 -6
  51. package/core/fail.js.flow +2 -2
  52. package/{_esm/core/fail.js → core/fail.mjs} +3 -3
  53. package/core/instanceOf.d.ts +3 -0
  54. package/core/instanceOf.js +2 -6
  55. package/core/instanceOf.js.flow +3 -3
  56. package/core/instanceOf.mjs +8 -0
  57. package/core/json.d.ts +11 -0
  58. package/core/json.js +3 -3
  59. package/core/json.js.flow +3 -3
  60. package/core/json.mjs +15 -0
  61. package/core/lazy.d.ts +3 -0
  62. package/{_esm/core/lazy.js → core/lazy.mjs} +0 -0
  63. package/core/number.d.ts +6 -0
  64. package/core/number.js +9 -13
  65. package/core/number.js.flow +18 -12
  66. package/core/number.mjs +25 -0
  67. package/core/object.d.ts +38 -0
  68. package/core/object.js +66 -13
  69. package/core/object.js.flow +84 -28
  70. package/{_esm/core/object.js → core/object.mjs} +64 -11
  71. package/core/optional.d.ts +5 -0
  72. package/core/optional.js +4 -8
  73. package/core/optional.js.flow +3 -3
  74. package/{_esm/core/optional.js → core/optional.mjs} +6 -6
  75. package/core/string.d.ts +13 -0
  76. package/core/string.js +31 -49
  77. package/core/string.js.flow +29 -39
  78. package/core/string.mjs +58 -0
  79. package/core/tuple.d.ts +30 -0
  80. package/core/tuple.js +30 -149
  81. package/core/tuple.js.flow +33 -197
  82. package/core/tuple.mjs +45 -0
  83. package/format.d.ts +4 -0
  84. package/{format/inline.js → format.js} +6 -1
  85. package/{_esm/format/inline.js.flow → format.js.flow} +6 -2
  86. package/{_esm/format/inline.js → format.mjs} +4 -1
  87. package/index.d.ts +42 -0
  88. package/index.js +33 -42
  89. package/index.js.flow +17 -18
  90. package/{_esm/index.js → index.mjs} +18 -19
  91. package/package.json +15 -3
  92. package/result.d.ts +39 -0
  93. package/result.js +9 -90
  94. package/result.js.flow +11 -87
  95. package/result.mjs +81 -0
  96. package/_esm/_guard.js.flow +0 -20
  97. package/_esm/_types.js.flow +0 -20
  98. package/_esm/_utils.js.flow +0 -97
  99. package/_esm/annotate.js.flow +0 -218
  100. package/_esm/core/array.js.flow +0 -103
  101. package/_esm/core/boolean.js.flow +0 -29
  102. package/_esm/core/composition.js +0 -42
  103. package/_esm/core/composition.js.flow +0 -43
  104. package/_esm/core/constants.js.flow +0 -46
  105. package/_esm/core/date.js.flow +0 -40
  106. package/_esm/core/describe.js.flow +0 -17
  107. package/_esm/core/dispatch.js.flow +0 -58
  108. package/_esm/core/either.js +0 -90
  109. package/_esm/core/either.js.flow +0 -151
  110. package/_esm/core/fail.js.flow +0 -12
  111. package/_esm/core/instanceOf.js +0 -8
  112. package/_esm/core/instanceOf.js.flow +0 -20
  113. package/_esm/core/json.js +0 -15
  114. package/_esm/core/json.js.flow +0 -28
  115. package/_esm/core/lazy.js.flow +0 -15
  116. package/_esm/core/mapping.js +0 -54
  117. package/_esm/core/mapping.js.flow +0 -54
  118. package/_esm/core/number.js +0 -25
  119. package/_esm/core/number.js.flow +0 -34
  120. package/_esm/core/object.js.flow +0 -203
  121. package/_esm/core/optional.js.flow +0 -41
  122. package/_esm/core/string.js +0 -76
  123. package/_esm/core/string.js.flow +0 -82
  124. package/_esm/core/tuple.js +0 -155
  125. package/_esm/core/tuple.js.flow +0 -215
  126. package/_esm/format/index.js +0 -2
  127. package/_esm/format/index.js.flow +0 -4
  128. package/_esm/format/short.js +0 -4
  129. package/_esm/format/short.js.flow +0 -8
  130. package/_esm/index.js.flow +0 -63
  131. package/_esm/result.js +0 -148
  132. package/_esm/result.js.flow +0 -174
  133. package/core/mapping.js +0 -67
  134. package/core/mapping.js.flow +0 -54
  135. package/format/index.js +0 -12
  136. package/format/index.js.flow +0 -4
  137. package/format/inline.js.flow +0 -122
  138. package/format/short.js +0 -10
  139. package/format/short.js.flow +0 -8
package/core/json.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import { Decoder } from '../_types';
2
+
3
+ export type JSONValue = null | string | number | boolean | JSONObject | JSONArray;
4
+ export interface JSONObject {
5
+ [key: string]: JSONValue;
6
+ }
7
+ export type JSONArray = JSONValue[];
8
+
9
+ export const json: Decoder<JSONValue>;
10
+ export const jsonArray: Decoder<JSONArray>;
11
+ export const jsonObject: Decoder<JSONObject>;
package/core/json.js CHANGED
@@ -7,7 +7,7 @@ var _array = require("./array");
7
7
 
8
8
  var _boolean2 = require("./boolean");
9
9
 
10
- var _mapping = require("./mapping");
10
+ var _object = require("./object");
11
11
 
12
12
  var _either = require("./either");
13
13
 
@@ -20,12 +20,12 @@ var _number = require("./number");
20
20
  var _string = require("./string");
21
21
 
22
22
  var jsonObject = (0, _lazy.lazy)(function () {
23
- return (0, _mapping.dict)(json);
23
+ return (0, _object.dict)(json);
24
24
  });
25
25
  exports.jsonObject = jsonObject;
26
26
  var jsonArray = (0, _lazy.lazy)(function () {
27
27
  return (0, _array.array)(json);
28
28
  });
29
29
  exports.jsonArray = jsonArray;
30
- var json = (0, _either.either6)(_constants.null_, _string.string, _number.number, _boolean2["boolean"], jsonObject, jsonArray);
30
+ var json = (0, _either.either)(_constants.null_, _string.string, _number.number, _boolean2["boolean"], jsonObject, jsonArray);
31
31
  exports.json = json;
package/core/json.js.flow CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  import { array } from './array';
4
4
  import { boolean } from './boolean';
5
- import { dict } from './mapping';
6
- import { either6 } from './either';
5
+ import { dict } from './object';
6
+ import { either } from './either';
7
7
  import { lazy } from './lazy';
8
8
  import { null_ } from './constants';
9
9
  import { number } from './number';
@@ -18,7 +18,7 @@ export const jsonObject: Decoder<JSONObject> = lazy(() => dict(json));
18
18
 
19
19
  export const jsonArray: Decoder<JSONArray> = lazy(() => array(json));
20
20
 
21
- export const json: Decoder<JSONValue> = either6(
21
+ export const json: Decoder<JSONValue> = either(
22
22
  null_,
23
23
  string,
24
24
  number,
package/core/json.mjs ADDED
@@ -0,0 +1,15 @@
1
+ import { array } from './array.mjs';
2
+ import { boolean as _boolean } from './boolean.mjs';
3
+ import { dict } from './object.mjs';
4
+ import { either } from './either.mjs';
5
+ import { lazy } from './lazy.mjs';
6
+ import { null_ } from './constants.mjs';
7
+ import { number } from './number.mjs';
8
+ import { string } from './string.mjs';
9
+ export var jsonObject = lazy(function () {
10
+ return dict(json);
11
+ });
12
+ export var jsonArray = lazy(function () {
13
+ return array(json);
14
+ });
15
+ export var json = either(null_, string, number, _boolean, jsonObject, jsonArray);
package/core/lazy.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { Decoder } from '../_types';
2
+
3
+ export function lazy<T>(decoderFn: () => Decoder<T>): Decoder<T>;
File without changes
@@ -0,0 +1,6 @@
1
+ import { Decoder } from '../_types';
2
+
3
+ export const integer: Decoder<number>;
4
+ export const number: Decoder<number>;
5
+ export const positiveInteger: Decoder<number>;
6
+ export const positiveNumber: Decoder<number>;
package/core/number.js CHANGED
@@ -3,18 +3,14 @@
3
3
  exports.__esModule = true;
4
4
  exports.positiveNumber = exports.positiveInteger = exports.number = exports.integer = void 0;
5
5
 
6
- var Result = _interopRequireWildcard(require("../result"));
7
-
8
6
  var _annotate = require("../annotate");
9
7
 
10
- var _composition = require("./composition");
11
-
12
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
8
+ var _result = require("../result");
13
9
 
14
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
10
+ var _composition = require("./composition");
15
11
 
16
12
  var anyNumber = function anyNumber(blob) {
17
- return typeof blob === 'number' && !Number.isNaN(blob) ? Result.ok(blob) : Result.err((0, _annotate.annotate)(blob, 'Must be number'));
13
+ return typeof blob === 'number' && !Number.isNaN(blob) ? (0, _result.ok)(blob) : (0, _result.err)((0, _annotate.annotate)(blob, 'Must be number'));
18
14
  };
19
15
 
20
16
  var isInteger = function isInteger(n) {
@@ -25,16 +21,16 @@ var isFinite = function isFinite(n) {
25
21
  return Number.isFinite(n);
26
22
  };
27
23
 
28
- var number = (0, _composition.compose)(anyNumber, (0, _composition.predicate)(isFinite, 'Number must be finite'));
24
+ var number = (0, _composition.predicate)(anyNumber, isFinite, 'Number must be finite');
29
25
  exports.number = number;
30
- var positiveNumber = (0, _composition.compose)(number, (0, _composition.predicate)(function (n) {
26
+ var positiveNumber = (0, _composition.predicate)(number, function (n) {
31
27
  return n >= 0;
32
- }, 'Number must be positive')); // Integers
28
+ }, 'Number must be positive'); // Integers
33
29
 
34
30
  exports.positiveNumber = positiveNumber;
35
- var integer = (0, _composition.compose)(number, (0, _composition.predicate)(isInteger, 'Number must be an integer'));
31
+ var integer = (0, _composition.predicate)(number, isInteger, 'Number must be an integer');
36
32
  exports.integer = integer;
37
- var positiveInteger = (0, _composition.compose)(integer, (0, _composition.predicate)(function (n) {
33
+ var positiveInteger = (0, _composition.predicate)(integer, function (n) {
38
34
  return n >= 0;
39
- }, 'Number must be positive'));
35
+ }, 'Number must be positive');
40
36
  exports.positiveInteger = positiveInteger;
@@ -1,34 +1,40 @@
1
1
  // @flow strict
2
2
 
3
- import * as Result from '../result';
4
3
  import { annotate } from '../annotate';
5
- import { compose, predicate } from './composition';
4
+ import { err, ok } from '../result';
5
+ import { predicate } from './composition';
6
6
  import type { Decoder } from '../_types';
7
7
 
8
8
  const anyNumber: Decoder<number> = (blob: mixed) => {
9
9
  return typeof blob === 'number' && !Number.isNaN(blob)
10
- ? Result.ok(blob)
11
- : Result.err(annotate(blob, 'Must be number'));
10
+ ? ok(blob)
11
+ : err(annotate(blob, 'Must be number'));
12
12
  };
13
13
 
14
14
  const isInteger = (n: number) => Number.isInteger(n);
15
15
  const isFinite = (n: number) => Number.isFinite(n);
16
16
 
17
- export const number: Decoder<number> = compose(
17
+ export const number: Decoder<number> = predicate(
18
18
  anyNumber,
19
- predicate(isFinite, 'Number must be finite'),
19
+ isFinite,
20
+ 'Number must be finite',
20
21
  );
21
- export const positiveNumber: Decoder<number> = compose(
22
+
23
+ export const positiveNumber: Decoder<number> = predicate(
22
24
  number,
23
- predicate((n) => n >= 0, 'Number must be positive'),
25
+ (n) => n >= 0,
26
+ 'Number must be positive',
24
27
  );
25
28
 
26
29
  // Integers
27
- export const integer: Decoder<number> = compose(
30
+ export const integer: Decoder<number> = predicate(
28
31
  number,
29
- predicate(isInteger, 'Number must be an integer'),
32
+ isInteger,
33
+ 'Number must be an integer',
30
34
  );
31
- export const positiveInteger: Decoder<number> = compose(
35
+
36
+ export const positiveInteger: Decoder<number> = predicate(
32
37
  integer,
33
- predicate((n) => n >= 0, 'Number must be positive'),
38
+ (n) => n >= 0,
39
+ 'Number must be positive',
34
40
  );
@@ -0,0 +1,25 @@
1
+ import { annotate } from '../annotate.mjs';
2
+ import { err, ok } from '../result.mjs';
3
+ import { predicate } from './composition.mjs';
4
+
5
+ var anyNumber = function anyNumber(blob) {
6
+ return typeof blob === 'number' && !Number.isNaN(blob) ? ok(blob) : err(annotate(blob, 'Must be number'));
7
+ };
8
+
9
+ var isInteger = function isInteger(n) {
10
+ return Number.isInteger(n);
11
+ };
12
+
13
+ var isFinite = function isFinite(n) {
14
+ return Number.isFinite(n);
15
+ };
16
+
17
+ export var number = predicate(anyNumber, isFinite, 'Number must be finite');
18
+ export var positiveNumber = predicate(number, function (n) {
19
+ return n >= 0;
20
+ }, 'Number must be positive'); // Integers
21
+
22
+ export var integer = predicate(number, isInteger, 'Number must be an integer');
23
+ export var positiveInteger = predicate(integer, function (n) {
24
+ return n >= 0;
25
+ }, 'Number must be positive');
@@ -0,0 +1,38 @@
1
+ /// <reference lib="es6" />
2
+
3
+ import { Decoder, DecoderType } from '../_types';
4
+ import { AllowImplicit } from './_helpers';
5
+
6
+ export type ObjectDecoderType<T> = AllowImplicit<{
7
+ [key in keyof T]: DecoderType<T[key]>;
8
+ }>;
9
+
10
+ export const pojo: Decoder<{ [key: string]: unknown }>;
11
+
12
+ export function object<O extends { [key: string]: Decoder<any> }>(
13
+ mapping: O,
14
+ ): Decoder<{ [K in keyof ObjectDecoderType<O>]: ObjectDecoderType<O>[K] }>;
15
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16
+ // This is basically just equivalent to:
17
+ // ObjectDecoderType<O>
18
+ //
19
+ // But by "resolving" this with a mapped type, we remove the helper
20
+ // type names from the inferred type here, making this much easier to
21
+ // work with while developing.
22
+
23
+ export function exact<O extends { [key: string]: Decoder<any> }>(
24
+ mapping: O,
25
+ ): Decoder<{ [K in keyof ObjectDecoderType<O>]: ObjectDecoderType<O>[K] }>;
26
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
27
+ // Ditto (see above)
28
+
29
+ export function inexact<O extends { [key: string]: Decoder<any> }>(
30
+ mapping: O,
31
+ ): Decoder<
32
+ { [K in keyof ObjectDecoderType<O>]: ObjectDecoderType<O>[K] } & {
33
+ [extra: string]: unknown;
34
+ }
35
+ >;
36
+
37
+ export function mapping<T>(decoder: Decoder<T>): Decoder<Map<string, T>>;
38
+ export function dict<T>(decoder: Decoder<T>): Decoder<{ [key: string]: T }>;
package/core/object.js CHANGED
@@ -1,20 +1,18 @@
1
1
  "use strict";
2
2
 
3
3
  exports.__esModule = true;
4
+ exports.dict = dict;
4
5
  exports.exact = exact;
5
6
  exports.inexact = inexact;
7
+ exports.mapping = mapping;
6
8
  exports.object = object;
7
9
  exports.pojo = void 0;
8
10
 
9
- var Result = _interopRequireWildcard(require("../result"));
10
-
11
11
  var _annotate = require("../annotate");
12
12
 
13
13
  var _composition = require("./composition");
14
14
 
15
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
16
-
17
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
15
+ var _result = require("../result");
18
16
 
19
17
  function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
20
18
 
@@ -36,7 +34,7 @@ function subtract(xs, ys) {
36
34
  }
37
35
 
38
36
  var pojo = function pojo(blob) {
39
- return isPojo(blob) ? Result.ok( // NOTE:
37
+ return isPojo(blob) ? (0, _result.ok)( // NOTE:
40
38
  // Since Flow 0.98, typeof o === 'object' refines to
41
39
  // {| +[string]: mixed |}
42
40
  // instead of
@@ -50,7 +48,7 @@ var pojo = function pojo(blob) {
50
48
  // way to turn a read-only Object to a writeable one in ES6 seems
51
49
  // to be to use object-spread. (Going off this benchmark:
52
50
  // https://thecodebarbarian.com/object-assign-vs-object-spread.html)
53
- _extends({}, blob)) : Result.err((0, _annotate.annotate)(blob, 'Must be an object'));
51
+ _extends({}, blob)) : (0, _result.err)((0, _annotate.annotate)(blob, 'Must be an object'));
54
52
  };
55
53
  /**
56
54
  * Given a mapping of fields-to-decoders, builds a decoder for an object type.
@@ -91,7 +89,7 @@ function object(mapping) {
91
89
  var rawValue = blob[key];
92
90
  var result = decoder(rawValue);
93
91
 
94
- if (result.type === 'ok') {
92
+ if (result.ok) {
95
93
  var value = result.value;
96
94
 
97
95
  if (value !== undefined) {
@@ -139,10 +137,10 @@ function object(mapping) {
139
137
  objAnn = (0, _annotate.updateText)(objAnn, "Missing " + pluralized + ": " + errMsg);
140
138
  }
141
139
 
142
- return Result.err(objAnn);
140
+ return (0, _result.err)(objAnn);
143
141
  }
144
142
 
145
- return Result.ok(record);
143
+ return (0, _result.ok)(record);
146
144
  });
147
145
  }
148
146
 
@@ -154,10 +152,10 @@ function exact(mapping) {
154
152
  var superfluous = subtract(actual, allowed);
155
153
 
156
154
  if (superfluous.size > 0) {
157
- return Result.err((0, _annotate.annotate)(blob, "Superfluous keys: " + Array.from(superfluous).join(', ')));
155
+ return (0, _result.err)((0, _annotate.annotate)(blob, "Superfluous keys: " + Array.from(superfluous).join(', ')));
158
156
  }
159
157
 
160
- return Result.ok(blob);
158
+ return (0, _result.ok)(blob);
161
159
  }); // Defer to the "object" decoder for doing the real decoding work. Since
162
160
  // we made sure there are no superfluous keys in this structure, it's now
163
161
  // safe to force-cast it to an $Exact<> type.
@@ -169,7 +167,7 @@ function exact(mapping) {
169
167
  function inexact(mapping) {
170
168
  return (0, _composition.compose)(pojo, function (blob) {
171
169
  var allkeys = new Set(Object.keys(blob));
172
- var decoder = (0, _composition.map)(object(mapping), function (safepart) {
170
+ var decoder = (0, _composition.transform)(object(mapping), function (safepart) {
173
171
  var safekeys = new Set(Object.keys(mapping)); // To account for hard-coded keys that aren't part of the input
174
172
 
175
173
  safekeys.forEach(function (k) {
@@ -191,4 +189,59 @@ function inexact(mapping) {
191
189
  });
192
190
  return decoder(blob);
193
191
  });
192
+ }
193
+ /**
194
+ * Like mapping(), but returns an object rather than a Map instance.
195
+ */
196
+
197
+
198
+ function dict(decoder) {
199
+ return (0, _composition.compose)(pojo, function (blob) {
200
+ var rv = {};
201
+ var errors = null;
202
+ Object.keys(blob).forEach(function (key) {
203
+ var value = blob[key];
204
+ var result = decoder(value);
205
+
206
+ if (result.ok) {
207
+ if (errors === null) {
208
+ rv[key] = result.value;
209
+ }
210
+ } else {
211
+ rv = {}; // Clear the success value so it can get garbage collected early
212
+
213
+ if (errors === null) {
214
+ errors = {};
215
+ }
216
+
217
+ errors[key] = result.error;
218
+ }
219
+ });
220
+
221
+ if (errors !== null) {
222
+ return (0, _result.err)((0, _annotate.merge)((0, _annotate.annotateObject)(blob), errors));
223
+ } else {
224
+ return (0, _result.ok)(rv);
225
+ }
226
+ });
227
+ }
228
+ /**
229
+ * Given an object, will decode a Map of string keys to whatever values.
230
+ *
231
+ * For example, given a decoder for a Person, we can verify a Person lookup
232
+ * table structure (of type Map<string, Person>) like so:
233
+ *
234
+ * mapping(person)
235
+ *
236
+ */
237
+
238
+
239
+ function mapping(decoder) {
240
+ return (0, _composition.transform)(dict(decoder), function (obj) {
241
+ return new Map( // This is effectively Object.entries(obj), but in a way that Flow
242
+ // will know the types are okay
243
+ Object.keys(obj).map(function (key) {
244
+ return [key, obj[key]];
245
+ }));
246
+ });
194
247
  }
@@ -1,10 +1,10 @@
1
1
  // @flow strict
2
2
 
3
- import * as Result from '../result';
4
3
  import { annotate, annotateObject, merge, updateText } from '../annotate';
5
- import { compose, map } from './composition';
4
+ import { compose, transform } from './composition';
5
+ import { err, ok } from '../result';
6
6
  import type { Annotation } from '../annotate';
7
- import type { Decoder, DecoderType } from '../_types';
7
+ import type { Decoder, DecodeResult, DecoderType } from '../_types';
8
8
 
9
9
  // $FlowFixMe[unclear-type] (not really an issue) - deliberate use of `any` - not sure how we should get rid of this
10
10
  type AnyDecoder = any;
@@ -36,7 +36,7 @@ function subtract(xs: Set<string>, ys: Set<string>): Set<string> {
36
36
 
37
37
  export const pojo: Decoder<{| [string]: mixed |}> = (blob: mixed) => {
38
38
  return isPojo(blob)
39
- ? Result.ok(
39
+ ? ok(
40
40
  // NOTE:
41
41
  // Since Flow 0.98, typeof o === 'object' refines to
42
42
  // {| +[string]: mixed |}
@@ -53,7 +53,7 @@ export const pojo: Decoder<{| [string]: mixed |}> = (blob: mixed) => {
53
53
  // https://thecodebarbarian.com/object-assign-vs-object-spread.html)
54
54
  { ...blob },
55
55
  )
56
- : Result.err(annotate(blob, 'Must be an object'));
56
+ : err(annotate(blob, 'Must be an object'));
57
57
  };
58
58
 
59
59
  /**
@@ -94,9 +94,9 @@ export function object<O: { +[field: string]: AnyDecoder, ... }>(
94
94
  Object.keys(mapping).forEach((key) => {
95
95
  const decoder = mapping[key];
96
96
  const rawValue = blob[key];
97
- const result = decoder(rawValue);
97
+ const result: DecodeResult<mixed> = decoder(rawValue);
98
98
 
99
- if (result.type === 'ok') {
99
+ if (result.ok) {
100
100
  const value = result.value;
101
101
  if (value !== undefined) {
102
102
  record[key] = value;
@@ -144,10 +144,10 @@ export function object<O: { +[field: string]: AnyDecoder, ... }>(
144
144
  objAnn = updateText(objAnn, `Missing ${pluralized}: ${errMsg}`);
145
145
  }
146
146
 
147
- return Result.err(objAnn);
147
+ return err(objAnn);
148
148
  }
149
149
 
150
- return Result.ok(record);
150
+ return ok(record);
151
151
  });
152
152
  }
153
153
 
@@ -160,11 +160,11 @@ export function exact<O: { +[field: string]: AnyDecoder, ... }>(
160
160
  const actual = new Set(Object.keys(blob));
161
161
  const superfluous = subtract(actual, allowed);
162
162
  if (superfluous.size > 0) {
163
- return Result.err(
163
+ return err(
164
164
  annotate(blob, `Superfluous keys: ${Array.from(superfluous).join(', ')}`),
165
165
  );
166
166
  }
167
- return Result.ok(blob);
167
+ return ok(blob);
168
168
  });
169
169
 
170
170
  // Defer to the "object" decoder for doing the real decoding work. Since
@@ -179,25 +179,81 @@ export function inexact<O: { +[field: string]: AnyDecoder }>(
179
179
  ): Decoder<$ObjMap<O, DecoderType> & { +[string]: mixed }> {
180
180
  return compose(pojo, (blob: {| [string]: mixed |}) => {
181
181
  const allkeys = new Set(Object.keys(blob));
182
- const decoder = map(object(mapping), (safepart: $ObjMap<O, DecoderType>) => {
183
- const safekeys = new Set(Object.keys(mapping));
184
-
185
- // To account for hard-coded keys that aren't part of the input
186
- safekeys.forEach((k) => allkeys.add(k));
187
-
188
- const rv = {};
189
- allkeys.forEach((k) => {
190
- if (safekeys.has(k)) {
191
- const value = safepart[k];
192
- if (value !== undefined) {
193
- rv[k] = value;
182
+ const decoder = transform(
183
+ object(mapping),
184
+ (safepart: $ObjMap<O, DecoderType>) => {
185
+ const safekeys = new Set(Object.keys(mapping));
186
+
187
+ // To account for hard-coded keys that aren't part of the input
188
+ safekeys.forEach((k) => allkeys.add(k));
189
+
190
+ const rv = {};
191
+ allkeys.forEach((k) => {
192
+ if (safekeys.has(k)) {
193
+ const value = safepart[k];
194
+ if (value !== undefined) {
195
+ rv[k] = value;
196
+ }
197
+ } else {
198
+ rv[k] = blob[k];
194
199
  }
195
- } else {
196
- rv[k] = blob[k];
200
+ });
201
+ return rv;
202
+ },
203
+ );
204
+ return decoder(blob);
205
+ });
206
+ }
207
+
208
+ /**
209
+ * Like mapping(), but returns an object rather than a Map instance.
210
+ */
211
+ export function dict<T>(decoder: Decoder<T>): Decoder<{ [string]: T }> {
212
+ return compose(pojo, (blob: { +[key: string]: mixed }) => {
213
+ let rv: { [key: string]: T } = {};
214
+ let errors: { [key: string]: Annotation } | null = null;
215
+
216
+ Object.keys(blob).forEach((key: string) => {
217
+ const value = blob[key];
218
+ const result = decoder(value);
219
+ if (result.ok) {
220
+ if (errors === null) {
221
+ rv[key] = result.value;
222
+ }
223
+ } else {
224
+ rv = {}; // Clear the success value so it can get garbage collected early
225
+ if (errors === null) {
226
+ errors = {};
197
227
  }
198
- });
199
- return rv;
228
+ errors[key] = result.error;
229
+ }
200
230
  });
201
- return decoder(blob);
231
+
232
+ if (errors !== null) {
233
+ return err(merge(annotateObject(blob), errors));
234
+ } else {
235
+ return ok(rv);
236
+ }
202
237
  });
203
238
  }
239
+
240
+ /**
241
+ * Given an object, will decode a Map of string keys to whatever values.
242
+ *
243
+ * For example, given a decoder for a Person, we can verify a Person lookup
244
+ * table structure (of type Map<string, Person>) like so:
245
+ *
246
+ * mapping(person)
247
+ *
248
+ */
249
+ export function mapping<T>(decoder: Decoder<T>): Decoder<Map<string, T>> {
250
+ return transform(
251
+ dict(decoder),
252
+ (obj) =>
253
+ new Map(
254
+ // This is effectively Object.entries(obj), but in a way that Flow
255
+ // will know the types are okay
256
+ Object.keys(obj).map((key) => [key, obj[key]]),
257
+ ),
258
+ );
259
+ }