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
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
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); }
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { annotate, annotateObject, merge, updateText } from '../annotate.mjs';
|
|
4
|
+
import { compose, transform } from './composition.mjs';
|
|
5
|
+
import { err, ok } from '../result.mjs';
|
|
6
6
|
|
|
7
7
|
function isPojo(o) {
|
|
8
8
|
return o !== null && o !== undefined && typeof o === 'object' && // This still seems to be the only reliable way to determine whether
|
|
@@ -22,7 +22,7 @@ function subtract(xs, ys) {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export var pojo = function pojo(blob) {
|
|
25
|
-
return isPojo(blob) ?
|
|
25
|
+
return isPojo(blob) ? ok( // NOTE:
|
|
26
26
|
// Since Flow 0.98, typeof o === 'object' refines to
|
|
27
27
|
// {| +[string]: mixed |}
|
|
28
28
|
// instead of
|
|
@@ -36,7 +36,7 @@ export var pojo = function pojo(blob) {
|
|
|
36
36
|
// way to turn a read-only Object to a writeable one in ES6 seems
|
|
37
37
|
// to be to use object-spread. (Going off this benchmark:
|
|
38
38
|
// https://thecodebarbarian.com/object-assign-vs-object-spread.html)
|
|
39
|
-
_extends({}, blob)) :
|
|
39
|
+
_extends({}, blob)) : err(annotate(blob, 'Must be an object'));
|
|
40
40
|
};
|
|
41
41
|
/**
|
|
42
42
|
* Given a mapping of fields-to-decoders, builds a decoder for an object type.
|
|
@@ -74,7 +74,7 @@ export function object(mapping) {
|
|
|
74
74
|
var rawValue = blob[key];
|
|
75
75
|
var result = decoder(rawValue);
|
|
76
76
|
|
|
77
|
-
if (result.
|
|
77
|
+
if (result.ok) {
|
|
78
78
|
var value = result.value;
|
|
79
79
|
|
|
80
80
|
if (value !== undefined) {
|
|
@@ -122,10 +122,10 @@ export function object(mapping) {
|
|
|
122
122
|
objAnn = updateText(objAnn, "Missing " + pluralized + ": " + errMsg);
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
return
|
|
125
|
+
return err(objAnn);
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
return
|
|
128
|
+
return ok(record);
|
|
129
129
|
});
|
|
130
130
|
}
|
|
131
131
|
export function exact(mapping) {
|
|
@@ -136,10 +136,10 @@ export function exact(mapping) {
|
|
|
136
136
|
var superfluous = subtract(actual, allowed);
|
|
137
137
|
|
|
138
138
|
if (superfluous.size > 0) {
|
|
139
|
-
return
|
|
139
|
+
return err(annotate(blob, "Superfluous keys: " + Array.from(superfluous).join(', ')));
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
return
|
|
142
|
+
return ok(blob);
|
|
143
143
|
}); // Defer to the "object" decoder for doing the real decoding work. Since
|
|
144
144
|
// we made sure there are no superfluous keys in this structure, it's now
|
|
145
145
|
// safe to force-cast it to an $Exact<> type.
|
|
@@ -150,7 +150,7 @@ export function exact(mapping) {
|
|
|
150
150
|
export function inexact(mapping) {
|
|
151
151
|
return compose(pojo, function (blob) {
|
|
152
152
|
var allkeys = new Set(Object.keys(blob));
|
|
153
|
-
var decoder =
|
|
153
|
+
var decoder = transform(object(mapping), function (safepart) {
|
|
154
154
|
var safekeys = new Set(Object.keys(mapping)); // To account for hard-coded keys that aren't part of the input
|
|
155
155
|
|
|
156
156
|
safekeys.forEach(function (k) {
|
|
@@ -172,4 +172,57 @@ export function inexact(mapping) {
|
|
|
172
172
|
});
|
|
173
173
|
return decoder(blob);
|
|
174
174
|
});
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Like mapping(), but returns an object rather than a Map instance.
|
|
178
|
+
*/
|
|
179
|
+
|
|
180
|
+
export function dict(decoder) {
|
|
181
|
+
return compose(pojo, function (blob) {
|
|
182
|
+
var rv = {};
|
|
183
|
+
var errors = null;
|
|
184
|
+
Object.keys(blob).forEach(function (key) {
|
|
185
|
+
var value = blob[key];
|
|
186
|
+
var result = decoder(value);
|
|
187
|
+
|
|
188
|
+
if (result.ok) {
|
|
189
|
+
if (errors === null) {
|
|
190
|
+
rv[key] = result.value;
|
|
191
|
+
}
|
|
192
|
+
} else {
|
|
193
|
+
rv = {}; // Clear the success value so it can get garbage collected early
|
|
194
|
+
|
|
195
|
+
if (errors === null) {
|
|
196
|
+
errors = {};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
errors[key] = result.error;
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
if (errors !== null) {
|
|
204
|
+
return err(merge(annotateObject(blob), errors));
|
|
205
|
+
} else {
|
|
206
|
+
return ok(rv);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Given an object, will decode a Map of string keys to whatever values.
|
|
212
|
+
*
|
|
213
|
+
* For example, given a decoder for a Person, we can verify a Person lookup
|
|
214
|
+
* table structure (of type Map<string, Person>) like so:
|
|
215
|
+
*
|
|
216
|
+
* mapping(person)
|
|
217
|
+
*
|
|
218
|
+
*/
|
|
219
|
+
|
|
220
|
+
export function mapping(decoder) {
|
|
221
|
+
return transform(dict(decoder), function (obj) {
|
|
222
|
+
return new Map( // This is effectively Object.entries(obj), but in a way that Flow
|
|
223
|
+
// will know the types are okay
|
|
224
|
+
Object.keys(obj).map(function (key) {
|
|
225
|
+
return [key, obj[key]];
|
|
226
|
+
}));
|
|
227
|
+
});
|
|
175
228
|
}
|
package/core/optional.js
CHANGED
|
@@ -5,17 +5,13 @@ exports.maybe = maybe;
|
|
|
5
5
|
exports.nullable = nullable;
|
|
6
6
|
exports.optional = optional;
|
|
7
7
|
|
|
8
|
-
var Result = _interopRequireWildcard(require("../result"));
|
|
9
|
-
|
|
10
8
|
var _annotate = require("../annotate");
|
|
11
9
|
|
|
12
10
|
var _either = require("./either");
|
|
13
11
|
|
|
14
|
-
var
|
|
15
|
-
|
|
16
|
-
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); }
|
|
12
|
+
var _result = require("../result");
|
|
17
13
|
|
|
18
|
-
|
|
14
|
+
var _constants = require("./constants");
|
|
19
15
|
|
|
20
16
|
/**
|
|
21
17
|
* Builds a Decoder that returns Ok for either `undefined` or `T` values,
|
|
@@ -41,8 +37,8 @@ function nullable(decoder) {
|
|
|
41
37
|
|
|
42
38
|
|
|
43
39
|
var undefined_or_null = function undefined_or_null(blob) {
|
|
44
|
-
return blob === undefined || blob === null ?
|
|
45
|
-
|
|
40
|
+
return blob === undefined || blob === null ? (0, _result.ok)(blob) : // Combine error message into a single line
|
|
41
|
+
(0, _result.err)((0, _annotate.annotate)(blob, 'Must be undefined or null'));
|
|
46
42
|
};
|
|
47
43
|
/**
|
|
48
44
|
* Decoder that only returns Ok for `null` or `undefined` inputs.
|
package/core/optional.js.flow
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// @flow strict
|
|
2
2
|
|
|
3
|
-
import * as Result from '../result';
|
|
4
3
|
import { annotate } from '../annotate';
|
|
5
4
|
import { either } from './either';
|
|
5
|
+
import { err, ok } from '../result';
|
|
6
6
|
import { null_, undefined_ } from './constants';
|
|
7
7
|
import type { Decoder } from '../_types';
|
|
8
8
|
|
|
@@ -29,9 +29,9 @@ export function nullable<T>(decoder: Decoder<T>): Decoder<null | T> {
|
|
|
29
29
|
*/
|
|
30
30
|
const undefined_or_null: Decoder<null | void> = (blob: mixed) =>
|
|
31
31
|
blob === undefined || blob === null
|
|
32
|
-
?
|
|
32
|
+
? ok(blob)
|
|
33
33
|
: // Combine error message into a single line
|
|
34
|
-
|
|
34
|
+
err(annotate(blob, 'Must be undefined or null'));
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* Decoder that only returns Ok for `null` or `undefined` inputs.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { null_, undefined_ } from './constants';
|
|
1
|
+
import { annotate } from '../annotate.mjs';
|
|
2
|
+
import { either } from './either.mjs';
|
|
3
|
+
import { err, ok } from '../result.mjs';
|
|
4
|
+
import { null_, undefined_ } from './constants.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Builds a Decoder that returns Ok for either `undefined` or `T` values,
|
|
@@ -25,8 +25,8 @@ export function nullable(decoder) {
|
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
27
|
var undefined_or_null = function undefined_or_null(blob) {
|
|
28
|
-
return blob === undefined || blob === null ?
|
|
29
|
-
|
|
28
|
+
return blob === undefined || blob === null ? ok(blob) : // Combine error message into a single line
|
|
29
|
+
err(annotate(blob, 'Must be undefined or null'));
|
|
30
30
|
};
|
|
31
31
|
/**
|
|
32
32
|
* Decoder that only returns Ok for `null` or `undefined` inputs.
|
package/core/string.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
|
|
3
|
+
import { Decoder } from '../_types';
|
|
4
|
+
|
|
5
|
+
export const string: Decoder<string>;
|
|
6
|
+
export const nonEmptyString: Decoder<string>;
|
|
7
|
+
export function regex(regex: RegExp, msg: string): Decoder<string>;
|
|
8
|
+
export const email: Decoder<string>;
|
|
9
|
+
export const url: Decoder<URL>;
|
|
10
|
+
export const httpsUrl: Decoder<URL>;
|
|
11
|
+
export const uuid: Decoder<string>;
|
|
12
|
+
export const uuidv1: Decoder<string>;
|
|
13
|
+
export const uuidv4: Decoder<string>;
|
package/core/string.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
exports.__esModule = true;
|
|
4
|
-
exports.nonEmptyString = exports.email = void 0;
|
|
4
|
+
exports.nonEmptyString = exports.httpsUrl = exports.email = void 0;
|
|
5
5
|
exports.regex = regex;
|
|
6
|
-
exports.url = exports.string = void 0;
|
|
7
|
-
|
|
8
|
-
var Result = _interopRequireWildcard(require("../result"));
|
|
6
|
+
exports.uuidv4 = exports.uuidv1 = exports.uuid = exports.url = exports.string = void 0;
|
|
9
7
|
|
|
10
8
|
var _annotate = require("../annotate");
|
|
11
9
|
|
|
12
|
-
var
|
|
10
|
+
var _either = require("./either");
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
var _result = require("../result");
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
var _instanceOf = require("./instanceOf");
|
|
15
|
+
|
|
16
|
+
var _composition = require("./composition");
|
|
17
17
|
|
|
18
18
|
/** Match groups in this regex:
|
|
19
19
|
* \1 - the scheme
|
|
@@ -22,15 +22,13 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
|
|
|
22
22
|
* \4 - the port (optional)
|
|
23
23
|
* \5 - the path (optional)
|
|
24
24
|
*/
|
|
25
|
-
var url_re = /^([A-Za-z]{3,9}(?:[+][A-Za-z]{3,9})?):\/\/(?:([-;:&=+$,\w]+)@)?(?:([A-Za-z0-9.-]+)(?::([0-9]{2,5}))?)(\/(?:[-+~%/.,\w]*)?(?:\?[-+=&;%@.,\w]*)?(?:#[.,!/\w]*)?)?$/;
|
|
26
|
-
|
|
27
|
-
var DEFAULT_SCHEMES = ['https'];
|
|
25
|
+
var url_re = /^([A-Za-z]{3,9}(?:[+][A-Za-z]{3,9})?):\/\/(?:([-;:&=+$,\w]+)@)?(?:([A-Za-z0-9.-]+)(?::([0-9]{2,5}))?)(\/(?:[-+~%/.,\w]*)?(?:\?[-+=&;%@.,\w]*)?(?:#[.,!/\w]*)?)?$/;
|
|
28
26
|
/**
|
|
29
27
|
* Decoder that only returns Ok for string inputs. Err otherwise.
|
|
30
28
|
*/
|
|
31
29
|
|
|
32
30
|
var string = function string(blob) {
|
|
33
|
-
return typeof blob === 'string' ?
|
|
31
|
+
return typeof blob === 'string' ? (0, _result.ok)(blob) : (0, _result.err)((0, _annotate.annotate)(blob, 'Must be string'));
|
|
34
32
|
};
|
|
35
33
|
/**
|
|
36
34
|
* Decoder that only returns Ok for non-empty string inputs. Err otherwise.
|
|
@@ -48,9 +46,9 @@ var nonEmptyString = regex(/\S/, 'Must be non-empty string');
|
|
|
48
46
|
exports.nonEmptyString = nonEmptyString;
|
|
49
47
|
|
|
50
48
|
function regex(regex, msg) {
|
|
51
|
-
return (0, _composition.
|
|
49
|
+
return (0, _composition.predicate)(string, function (s) {
|
|
52
50
|
return regex.test(s);
|
|
53
|
-
}, msg)
|
|
51
|
+
}, msg);
|
|
54
52
|
}
|
|
55
53
|
/**
|
|
56
54
|
* Decoder that only returns Ok for string inputs that match the almost perfect
|
|
@@ -59,40 +57,24 @@ function regex(regex, msg) {
|
|
|
59
57
|
|
|
60
58
|
|
|
61
59
|
var email = regex(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/, 'Must be email');
|
|
62
|
-
/**
|
|
63
|
-
* Decoder that only returns Ok for string inputs that match URLs of the
|
|
64
|
-
* expected scheme. Defaults to only accept HTTPS URLs. Err otherwise.
|
|
65
|
-
*
|
|
66
|
-
* Variants that can be used:
|
|
67
|
-
*
|
|
68
|
-
* - url() accepts only https:// URLs
|
|
69
|
-
* - url([]) accepts any URL scheme
|
|
70
|
-
* - url(['http']) accepts only HTTP
|
|
71
|
-
* - url(['https', 'git+ssh']) accepts both https:// and git+ssh:// URLs
|
|
72
|
-
*/
|
|
73
|
-
|
|
74
60
|
exports.email = email;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
});
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
exports.url = url;
|
|
61
|
+
var url = (0, _either.either)((0, _composition.transform)(regex(url_re, 'Must be URL'), function (value) {
|
|
62
|
+
return new URL(value);
|
|
63
|
+
}), (0, _instanceOf.instanceOf)(URL));
|
|
64
|
+
exports.url = url;
|
|
65
|
+
var httpsUrl = (0, _composition.predicate)(url, function (value) {
|
|
66
|
+
return value.protocol === 'https:';
|
|
67
|
+
}, 'Must be an HTTPS URL');
|
|
68
|
+
exports.httpsUrl = httpsUrl;
|
|
69
|
+
var uuid = regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, 'Must be uuid');
|
|
70
|
+
exports.uuid = uuid;
|
|
71
|
+
var uuidv1 = // https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address)
|
|
72
|
+
(0, _composition.predicate)(uuid, function (value) {
|
|
73
|
+
return value[14] === '1';
|
|
74
|
+
}, 'Must be uuidv1');
|
|
75
|
+
exports.uuidv1 = uuidv1;
|
|
76
|
+
var uuidv4 = // https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)
|
|
77
|
+
(0, _composition.predicate)(uuid, function (value) {
|
|
78
|
+
return value[14] === '4';
|
|
79
|
+
}, 'Must be uuidv4');
|
|
80
|
+
exports.uuidv4 = uuidv4;
|
package/core/string.js.flow
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
// @flow strict
|
|
2
2
|
|
|
3
|
-
import * as Result from '../result';
|
|
4
3
|
import { annotate } from '../annotate';
|
|
5
|
-
import {
|
|
4
|
+
import { either } from './either';
|
|
5
|
+
import { err, ok } from '../result';
|
|
6
|
+
import { instanceOf } from './instanceOf';
|
|
7
|
+
import { predicate, transform } from './composition';
|
|
6
8
|
import type { Decoder } from '../_types';
|
|
7
9
|
|
|
8
10
|
/** Match groups in this regex:
|
|
@@ -15,16 +17,11 @@ import type { Decoder } from '../_types';
|
|
|
15
17
|
const url_re =
|
|
16
18
|
/^([A-Za-z]{3,9}(?:[+][A-Za-z]{3,9})?):\/\/(?:([-;:&=+$,\w]+)@)?(?:([A-Za-z0-9.-]+)(?::([0-9]{2,5}))?)(\/(?:[-+~%/.,\w]*)?(?:\?[-+=&;%@.,\w]*)?(?:#[.,!/\w]*)?)?$/;
|
|
17
19
|
|
|
18
|
-
// The URL schemes the url() decoder accepts by default
|
|
19
|
-
const DEFAULT_SCHEMES = ['https'];
|
|
20
|
-
|
|
21
20
|
/**
|
|
22
21
|
* Decoder that only returns Ok for string inputs. Err otherwise.
|
|
23
22
|
*/
|
|
24
23
|
export const string: Decoder<string> = (blob: mixed) => {
|
|
25
|
-
return typeof blob === 'string'
|
|
26
|
-
? Result.ok(blob)
|
|
27
|
-
: Result.err(annotate(blob, 'Must be string'));
|
|
24
|
+
return typeof blob === 'string' ? ok(blob) : err(annotate(blob, 'Must be string'));
|
|
28
25
|
};
|
|
29
26
|
|
|
30
27
|
/**
|
|
@@ -38,10 +35,7 @@ export const nonEmptyString: Decoder<string> = regex(/\S/, 'Must be non-empty st
|
|
|
38
35
|
* before testing the regex.
|
|
39
36
|
*/
|
|
40
37
|
export function regex(regex: RegExp, msg: string): Decoder<string> {
|
|
41
|
-
return
|
|
42
|
-
string,
|
|
43
|
-
predicate((s) => regex.test(s), msg),
|
|
44
|
-
);
|
|
38
|
+
return predicate(string, (s) => regex.test(s), msg);
|
|
45
39
|
}
|
|
46
40
|
|
|
47
41
|
/**
|
|
@@ -53,30 +47,26 @@ export const email: Decoder<string> = regex(
|
|
|
53
47
|
'Must be email',
|
|
54
48
|
);
|
|
55
49
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
export const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
});
|
|
50
|
+
export const url: Decoder<URL> = either(
|
|
51
|
+
transform(regex(url_re, 'Must be URL'), (value) => new URL(value)),
|
|
52
|
+
instanceOf(URL),
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
export const httpsUrl: Decoder<URL> = predicate(
|
|
56
|
+
url,
|
|
57
|
+
(value) => value.protocol === 'https:',
|
|
58
|
+
'Must be an HTTPS URL',
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
export const uuid: Decoder<string> = regex(
|
|
62
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
|
|
63
|
+
'Must be uuid',
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
export const uuidv1: Decoder<string> =
|
|
67
|
+
// https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address)
|
|
68
|
+
predicate(uuid, (value) => value[14] === '1', 'Must be uuidv1');
|
|
69
|
+
|
|
70
|
+
export const uuidv4: Decoder<string> =
|
|
71
|
+
// https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)
|
|
72
|
+
predicate(uuid, (value) => value[14] === '4', 'Must be uuidv4');
|
package/core/string.mjs
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { annotate } from '../annotate.mjs';
|
|
2
|
+
import { either } from './either.mjs';
|
|
3
|
+
import { err, ok } from '../result.mjs';
|
|
4
|
+
import { instanceOf } from './instanceOf.mjs';
|
|
5
|
+
import { predicate, transform } from './composition.mjs';
|
|
6
|
+
|
|
7
|
+
/** Match groups in this regex:
|
|
8
|
+
* \1 - the scheme
|
|
9
|
+
* \2 - the username/password (optional)
|
|
10
|
+
* \3 - the host
|
|
11
|
+
* \4 - the port (optional)
|
|
12
|
+
* \5 - the path (optional)
|
|
13
|
+
*/
|
|
14
|
+
var url_re = /^([A-Za-z]{3,9}(?:[+][A-Za-z]{3,9})?):\/\/(?:([-;:&=+$,\w]+)@)?(?:([A-Za-z0-9.-]+)(?::([0-9]{2,5}))?)(\/(?:[-+~%/.,\w]*)?(?:\?[-+=&;%@.,\w]*)?(?:#[.,!/\w]*)?)?$/;
|
|
15
|
+
/**
|
|
16
|
+
* Decoder that only returns Ok for string inputs. Err otherwise.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
export var string = function string(blob) {
|
|
20
|
+
return typeof blob === 'string' ? ok(blob) : err(annotate(blob, 'Must be string'));
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Decoder that only returns Ok for non-empty string inputs. Err otherwise.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
export var nonEmptyString = regex(/\S/, 'Must be non-empty string');
|
|
27
|
+
/**
|
|
28
|
+
* Decoder that only returns Ok for string inputs that match the regular
|
|
29
|
+
* expression. Err otherwise. Will always validate that the input is a string
|
|
30
|
+
* before testing the regex.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
export function regex(regex, msg) {
|
|
34
|
+
return predicate(string, function (s) {
|
|
35
|
+
return regex.test(s);
|
|
36
|
+
}, msg);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Decoder that only returns Ok for string inputs that match the almost perfect
|
|
40
|
+
* email regex, taken from http://emailregex.com. Err otherwise.
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
export var email = regex(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/, 'Must be email');
|
|
44
|
+
export var url = either(transform(regex(url_re, 'Must be URL'), function (value) {
|
|
45
|
+
return new URL(value);
|
|
46
|
+
}), instanceOf(URL));
|
|
47
|
+
export var httpsUrl = predicate(url, function (value) {
|
|
48
|
+
return value.protocol === 'https:';
|
|
49
|
+
}, 'Must be an HTTPS URL');
|
|
50
|
+
export var uuid = regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, 'Must be uuid');
|
|
51
|
+
export var uuidv1 = // https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address)
|
|
52
|
+
predicate(uuid, function (value) {
|
|
53
|
+
return value[14] === '1';
|
|
54
|
+
}, 'Must be uuidv1');
|
|
55
|
+
export var uuidv4 = // https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)
|
|
56
|
+
predicate(uuid, function (value) {
|
|
57
|
+
return value[14] === '4';
|
|
58
|
+
}, 'Must be uuidv4');
|
package/core/tuple.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Decoder } from '../_types';
|
|
2
|
+
|
|
3
|
+
export function tuple<A>(a: Decoder<A>): Decoder<[A]>;
|
|
4
|
+
export function tuple<A, B>(a: Decoder<A>, b: Decoder<B>): Decoder<[A, B]>;
|
|
5
|
+
export function tuple<A, B, C>(
|
|
6
|
+
a: Decoder<A>,
|
|
7
|
+
b: Decoder<B>,
|
|
8
|
+
c: Decoder<C>,
|
|
9
|
+
): Decoder<[A, B, C]>;
|
|
10
|
+
export function tuple<A, B, C, D>(
|
|
11
|
+
a: Decoder<A>,
|
|
12
|
+
b: Decoder<B>,
|
|
13
|
+
c: Decoder<C>,
|
|
14
|
+
d: Decoder<D>,
|
|
15
|
+
): Decoder<[A, B, C, D]>;
|
|
16
|
+
export function tuple<A, B, C, D, E>(
|
|
17
|
+
a: Decoder<A>,
|
|
18
|
+
b: Decoder<B>,
|
|
19
|
+
c: Decoder<C>,
|
|
20
|
+
d: Decoder<D>,
|
|
21
|
+
e: Decoder<E>,
|
|
22
|
+
): Decoder<[A, B, C, D, E]>;
|
|
23
|
+
export function tuple<A, B, C, D, E, F>(
|
|
24
|
+
a: Decoder<A>,
|
|
25
|
+
b: Decoder<B>,
|
|
26
|
+
c: Decoder<C>,
|
|
27
|
+
d: Decoder<D>,
|
|
28
|
+
e: Decoder<E>,
|
|
29
|
+
f: Decoder<F>,
|
|
30
|
+
): Decoder<[A, B, C, D, E, F]>;
|