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/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
|
|
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,
|
|
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.
|
|
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 './
|
|
6
|
-
import {
|
|
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> =
|
|
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
|
File without changes
|
package/core/number.d.ts
ADDED
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
|
|
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
|
-
|
|
10
|
+
var _composition = require("./composition");
|
|
15
11
|
|
|
16
12
|
var anyNumber = function anyNumber(blob) {
|
|
17
|
-
return typeof blob === 'number' && !Number.isNaN(blob) ?
|
|
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.
|
|
24
|
+
var number = (0, _composition.predicate)(anyNumber, isFinite, 'Number must be finite');
|
|
29
25
|
exports.number = number;
|
|
30
|
-
var positiveNumber = (0, _composition.
|
|
26
|
+
var positiveNumber = (0, _composition.predicate)(number, function (n) {
|
|
31
27
|
return n >= 0;
|
|
32
|
-
}, 'Number must be positive')
|
|
28
|
+
}, 'Number must be positive'); // Integers
|
|
33
29
|
|
|
34
30
|
exports.positiveNumber = positiveNumber;
|
|
35
|
-
var integer = (0, _composition.
|
|
31
|
+
var integer = (0, _composition.predicate)(number, isInteger, 'Number must be an integer');
|
|
36
32
|
exports.integer = integer;
|
|
37
|
-
var positiveInteger = (0, _composition.
|
|
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;
|
package/core/number.js.flow
CHANGED
|
@@ -1,34 +1,40 @@
|
|
|
1
1
|
// @flow strict
|
|
2
2
|
|
|
3
|
-
import * as Result from '../result';
|
|
4
3
|
import { annotate } from '../annotate';
|
|
5
|
-
import {
|
|
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
|
-
?
|
|
11
|
-
:
|
|
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> =
|
|
17
|
+
export const number: Decoder<number> = predicate(
|
|
18
18
|
anyNumber,
|
|
19
|
-
|
|
19
|
+
isFinite,
|
|
20
|
+
'Number must be finite',
|
|
20
21
|
);
|
|
21
|
-
|
|
22
|
+
|
|
23
|
+
export const positiveNumber: Decoder<number> = predicate(
|
|
22
24
|
number,
|
|
23
|
-
|
|
25
|
+
(n) => n >= 0,
|
|
26
|
+
'Number must be positive',
|
|
24
27
|
);
|
|
25
28
|
|
|
26
29
|
// Integers
|
|
27
|
-
export const integer: Decoder<number> =
|
|
30
|
+
export const integer: Decoder<number> = predicate(
|
|
28
31
|
number,
|
|
29
|
-
|
|
32
|
+
isInteger,
|
|
33
|
+
'Number must be an integer',
|
|
30
34
|
);
|
|
31
|
-
|
|
35
|
+
|
|
36
|
+
export const positiveInteger: Decoder<number> = predicate(
|
|
32
37
|
integer,
|
|
33
|
-
|
|
38
|
+
(n) => n >= 0,
|
|
39
|
+
'Number must be positive',
|
|
34
40
|
);
|
package/core/number.mjs
ADDED
|
@@ -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');
|
package/core/object.d.ts
ADDED
|
@@ -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
|
-
|
|
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) ?
|
|
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)) :
|
|
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.
|
|
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
|
|
140
|
+
return (0, _result.err)(objAnn);
|
|
143
141
|
}
|
|
144
142
|
|
|
145
|
-
return
|
|
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
|
|
155
|
+
return (0, _result.err)((0, _annotate.annotate)(blob, "Superfluous keys: " + Array.from(superfluous).join(', ')));
|
|
158
156
|
}
|
|
159
157
|
|
|
160
|
-
return
|
|
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.
|
|
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
|
}
|
package/core/object.js.flow
CHANGED
|
@@ -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,
|
|
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
|
-
?
|
|
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
|
-
:
|
|
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.
|
|
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
|
|
147
|
+
return err(objAnn);
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
return
|
|
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
|
|
163
|
+
return err(
|
|
164
164
|
annotate(blob, `Superfluous keys: ${Array.from(superfluous).join(', ')}`),
|
|
165
165
|
);
|
|
166
166
|
}
|
|
167
|
-
return
|
|
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 =
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
if (
|
|
193
|
-
|
|
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
|
-
}
|
|
196
|
-
|
|
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
|
-
|
|
228
|
+
errors[key] = result.error;
|
|
229
|
+
}
|
|
200
230
|
});
|
|
201
|
-
|
|
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
|
+
}
|