decoders 2.0.0 → 2.0.1
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 +11 -0
- package/Decoder.js +41 -148
- package/Decoder.js.flow +1 -1
- package/Decoder.mjs +38 -145
- package/README.md +1 -1
- package/_utils.js +50 -61
- package/_utils.js.flow +18 -4
- package/_utils.mjs +41 -52
- package/annotate.js +79 -72
- package/annotate.mjs +62 -58
- package/format.js +64 -74
- package/format.js.flow +11 -11
- package/format.mjs +58 -68
- package/index.js +66 -66
- package/index.mjs +11 -11
- package/lib/arrays.js +47 -89
- package/lib/arrays.mjs +38 -78
- package/lib/basics.js +59 -109
- package/lib/basics.mjs +49 -94
- package/lib/booleans.js +14 -24
- package/lib/booleans.mjs +9 -19
- package/lib/dates.js +18 -34
- package/lib/dates.mjs +12 -27
- package/lib/json.d.ts +3 -3
- package/lib/json.js +20 -42
- package/lib/json.js.flow +2 -2
- package/lib/json.mjs +13 -35
- package/lib/numbers.js +19 -39
- package/lib/numbers.mjs +11 -31
- package/lib/objects.d.ts +11 -10
- package/lib/objects.js +84 -163
- package/lib/objects.js.flow +4 -12
- package/lib/objects.mjs +74 -150
- package/lib/strings.js +41 -84
- package/lib/strings.mjs +25 -67
- package/lib/unions.d.ts +1 -1
- package/lib/unions.js +52 -116
- package/lib/unions.js.flow +1 -1
- package/lib/unions.mjs +46 -109
- package/lib/utilities.d.ts +7 -1
- package/lib/utilities.js +23 -50
- package/lib/utilities.mjs +15 -38
- package/package.json +1 -1
- package/result.js +9 -22
- package/result.mjs +5 -17
package/lib/objects.mjs
CHANGED
|
@@ -1,223 +1,147 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import { define } from '../Decoder.mjs';
|
|
5
|
-
|
|
6
|
-
function subtract(xs, ys) {
|
|
7
|
-
var result = new Set();
|
|
8
|
-
xs.forEach(function (x) {
|
|
9
|
-
if (!ys.has(x)) {
|
|
10
|
-
result.add(x);
|
|
11
|
-
}
|
|
12
|
-
});
|
|
13
|
-
return result;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Accepts any "plain old JavaScript object", but doesn't validate its keys or
|
|
17
|
-
* values further.
|
|
18
|
-
*/
|
|
19
|
-
|
|
1
|
+
import { annotateObject, merge, updateText } from '../annotate.mjs'
|
|
2
|
+
import { define } from '../Decoder.mjs'
|
|
3
|
+
import { subtract } from '../_utils.mjs'
|
|
20
4
|
|
|
21
5
|
export var pojo = define(function (blob, ok, err) {
|
|
22
|
-
return blob !== null && blob !== undefined && typeof blob === 'object' &&
|
|
23
|
-
|
|
24
|
-
// $FlowFixMe[method-unbinding]
|
|
25
|
-
Object.prototype.toString.call(blob) === '[object Object]' ? ok( // NOTE:
|
|
26
|
-
// Since Flow 0.98, typeof o === 'object' refines to
|
|
27
|
-
// {| +[string]: mixed |}
|
|
28
|
-
// instead of
|
|
29
|
-
// {| [string]: mixed |}
|
|
30
|
-
//
|
|
31
|
-
// For rationale, see https://github.com/facebook/flow/issues/7685.
|
|
32
|
-
// In this case, we don't want to output a read-only version of
|
|
33
|
-
// the object because it's up to the user of decoders to
|
|
34
|
-
// determine what they want to do with the decoded output. If they
|
|
35
|
-
// want to write items into the array, that's fine! The fastest
|
|
36
|
-
// way to turn a read-only Object to a writeable one in ES6 seems
|
|
37
|
-
// to be to use object-spread. (Going off this benchmark:
|
|
38
|
-
// https://thecodebarbarian.com/object-assign-vs-object-spread.html)
|
|
39
|
-
_extends({}, blob)) : err('Must be an object');
|
|
40
|
-
});
|
|
41
|
-
/**
|
|
42
|
-
* Accepts objects with fields matching the given decoders. Extra fields that
|
|
43
|
-
* exist on the input object are ignored and will not be returned.
|
|
44
|
-
*/
|
|
6
|
+
return blob !== null && blob !== undefined && typeof blob === 'object' && Object.prototype.toString.call(blob) === '[object Object]' ? ok(blob) : err('Must be an object')
|
|
7
|
+
})
|
|
45
8
|
|
|
46
9
|
export function object(decodersByKey) {
|
|
47
|
-
|
|
48
|
-
var knownKeys = new Set(Object.keys(decodersByKey));
|
|
10
|
+
var knownKeys = new Set(Object.keys(decodersByKey))
|
|
49
11
|
return pojo.then(function (plainObj, ok, err) {
|
|
50
|
-
var actualKeys = new Set(Object.keys(plainObj))
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
var missingKeys = subtract(knownKeys, actualKeys);
|
|
56
|
-
var record = {};
|
|
57
|
-
var errors = null;
|
|
12
|
+
var actualKeys = new Set(Object.keys(plainObj))
|
|
13
|
+
|
|
14
|
+
var missingKeys = subtract(knownKeys, actualKeys)
|
|
15
|
+
var record = {}
|
|
16
|
+
var errors = null
|
|
58
17
|
Object.keys(decodersByKey).forEach(function (key) {
|
|
59
|
-
var decoder = decodersByKey[key]
|
|
60
|
-
var rawValue = plainObj[key]
|
|
61
|
-
var result = decoder.decode(rawValue)
|
|
18
|
+
var decoder = decodersByKey[key]
|
|
19
|
+
var rawValue = plainObj[key]
|
|
20
|
+
var result = decoder.decode(rawValue)
|
|
62
21
|
|
|
63
22
|
if (result.ok) {
|
|
64
|
-
var value = result.value
|
|
23
|
+
var value = result.value
|
|
65
24
|
|
|
66
25
|
if (value !== undefined) {
|
|
67
|
-
record[key] = value
|
|
68
|
-
}
|
|
69
|
-
// tracker
|
|
70
|
-
|
|
26
|
+
record[key] = value
|
|
27
|
+
}
|
|
71
28
|
|
|
72
|
-
missingKeys[
|
|
29
|
+
missingKeys['delete'](key)
|
|
73
30
|
} else {
|
|
74
|
-
var ann = result.error
|
|
75
|
-
// want to collect more error information.
|
|
31
|
+
var ann = result.error
|
|
76
32
|
|
|
77
33
|
if (rawValue === undefined) {
|
|
78
|
-
|
|
79
|
-
// undefined. This covers explicit undefineds to be
|
|
80
|
-
// treated the same as implicit undefineds (aka missing
|
|
81
|
-
// keys).
|
|
82
|
-
missingKeys.add(key);
|
|
34
|
+
missingKeys.add(key)
|
|
83
35
|
} else {
|
|
84
36
|
if (errors === null) {
|
|
85
|
-
errors = {}
|
|
37
|
+
errors = {}
|
|
86
38
|
}
|
|
87
39
|
|
|
88
|
-
errors[key] = ann
|
|
40
|
+
errors[key] = ann
|
|
89
41
|
}
|
|
90
42
|
}
|
|
91
|
-
})
|
|
92
|
-
// report. First of all, we want to report any inline errors in this
|
|
93
|
-
// object. Lastly, any fields that are missing should be annotated on
|
|
94
|
-
// the outer object itself.
|
|
43
|
+
})
|
|
95
44
|
|
|
96
45
|
if (errors || missingKeys.size > 0) {
|
|
97
|
-
var objAnn = annotateObject(plainObj)
|
|
46
|
+
var objAnn = annotateObject(plainObj)
|
|
98
47
|
|
|
99
48
|
if (errors) {
|
|
100
|
-
objAnn = merge(objAnn, errors)
|
|
49
|
+
objAnn = merge(objAnn, errors)
|
|
101
50
|
}
|
|
102
51
|
|
|
103
52
|
if (missingKeys.size > 0) {
|
|
104
|
-
var errMsg = Array.from(missingKeys)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
53
|
+
var errMsg = Array.from(missingKeys)
|
|
54
|
+
.map(function (key) {
|
|
55
|
+
return '"' + key + '"'
|
|
56
|
+
})
|
|
57
|
+
.join(', ')
|
|
58
|
+
var pluralized = missingKeys.size > 1 ? 'keys' : 'key'
|
|
59
|
+
objAnn = updateText(objAnn, 'Missing ' + pluralized + ': ' + errMsg)
|
|
109
60
|
}
|
|
110
61
|
|
|
111
|
-
return err(objAnn)
|
|
62
|
+
return err(objAnn)
|
|
112
63
|
}
|
|
113
64
|
|
|
114
|
-
return ok(record)
|
|
115
|
-
})
|
|
65
|
+
return ok(record)
|
|
66
|
+
})
|
|
116
67
|
}
|
|
117
|
-
/**
|
|
118
|
-
* Like `object()`, but will reject inputs that contain extra fields that are
|
|
119
|
-
* not specified explicitly.
|
|
120
|
-
*/
|
|
121
68
|
|
|
122
69
|
export function exact(decodersByKey) {
|
|
123
|
-
|
|
124
|
-
var allowedKeys = new Set(Object.keys(decodersByKey)); // Check the inputted object for any unexpected extra keys
|
|
70
|
+
var allowedKeys = new Set(Object.keys(decodersByKey))
|
|
125
71
|
|
|
126
72
|
var checked = pojo.reject(function (plainObj) {
|
|
127
|
-
var actualKeys = new Set(Object.keys(plainObj))
|
|
128
|
-
var extraKeys = subtract(actualKeys, allowedKeys)
|
|
129
|
-
return extraKeys.size > 0 ?
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
// safe to force-cast it to an $Exact<> type.
|
|
134
|
-
|
|
135
|
-
return checked.then(object(decodersByKey).decode);
|
|
73
|
+
var actualKeys = new Set(Object.keys(plainObj))
|
|
74
|
+
var extraKeys = subtract(actualKeys, allowedKeys)
|
|
75
|
+
return extraKeys.size > 0 ? 'Unexpected extra keys: ' + Array.from(extraKeys).join(', ') : null
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
return checked.then(object(decodersByKey).decode)
|
|
136
79
|
}
|
|
137
|
-
/**
|
|
138
|
-
* Like `object()`, but will pass through any extra fields on the input object
|
|
139
|
-
* unvalidated that will thus be of `unknown` type statically.
|
|
140
|
-
*/
|
|
141
80
|
|
|
142
81
|
export function inexact(decodersByKey) {
|
|
143
82
|
return pojo.then(function (plainObj) {
|
|
144
|
-
var allkeys = new Set(Object.keys(plainObj))
|
|
83
|
+
var allkeys = new Set(Object.keys(plainObj))
|
|
145
84
|
var decoder = object(decodersByKey).transform(function (safepart) {
|
|
146
|
-
var safekeys = new Set(Object.keys(decodersByKey))
|
|
85
|
+
var safekeys = new Set(Object.keys(decodersByKey))
|
|
147
86
|
|
|
148
87
|
safekeys.forEach(function (k) {
|
|
149
|
-
return allkeys.add(k)
|
|
150
|
-
})
|
|
151
|
-
var rv = {}
|
|
88
|
+
return allkeys.add(k)
|
|
89
|
+
})
|
|
90
|
+
var rv = {}
|
|
152
91
|
allkeys.forEach(function (k) {
|
|
153
92
|
if (safekeys.has(k)) {
|
|
154
|
-
var value = safepart[k]
|
|
93
|
+
var value = safepart[k]
|
|
155
94
|
|
|
156
95
|
if (value !== undefined) {
|
|
157
|
-
rv[k] = value
|
|
96
|
+
rv[k] = value
|
|
158
97
|
}
|
|
159
98
|
} else {
|
|
160
|
-
rv[k] = plainObj[k]
|
|
99
|
+
rv[k] = plainObj[k]
|
|
161
100
|
}
|
|
162
|
-
})
|
|
163
|
-
return rv
|
|
164
|
-
})
|
|
165
|
-
return decoder.decode(plainObj)
|
|
166
|
-
})
|
|
101
|
+
})
|
|
102
|
+
return rv
|
|
103
|
+
})
|
|
104
|
+
return decoder.decode(plainObj)
|
|
105
|
+
})
|
|
167
106
|
}
|
|
168
|
-
/**
|
|
169
|
-
* Accepts objects where all values match the given decoder, and returns the
|
|
170
|
-
* result as a `{ [string]: T }`.
|
|
171
|
-
*
|
|
172
|
-
* The main difference between `object()` and `dict()` is that you'd typically
|
|
173
|
-
* use `object()` if this is a record-like object, where all field names are
|
|
174
|
-
* known and the values are heterogeneous. Whereas with `dict()` the keys are
|
|
175
|
-
* typically dynamic and the values homogeneous, like in a dictionary,
|
|
176
|
-
* a lookup table, or a cache.
|
|
177
|
-
*/
|
|
178
107
|
|
|
179
108
|
export function dict(decoder) {
|
|
180
109
|
return pojo.then(function (plainObj, ok, err) {
|
|
181
|
-
var rv = {}
|
|
182
|
-
var errors = null
|
|
110
|
+
var rv = {}
|
|
111
|
+
var errors = null
|
|
183
112
|
Object.keys(plainObj).forEach(function (key) {
|
|
184
|
-
var value = plainObj[key]
|
|
185
|
-
var result = decoder.decode(value)
|
|
113
|
+
var value = plainObj[key]
|
|
114
|
+
var result = decoder.decode(value)
|
|
186
115
|
|
|
187
116
|
if (result.ok) {
|
|
188
117
|
if (errors === null) {
|
|
189
|
-
rv[key] = result.value
|
|
118
|
+
rv[key] = result.value
|
|
190
119
|
}
|
|
191
120
|
} else {
|
|
192
|
-
rv = {}
|
|
121
|
+
rv = {}
|
|
193
122
|
|
|
194
123
|
if (errors === null) {
|
|
195
|
-
errors = {}
|
|
124
|
+
errors = {}
|
|
196
125
|
}
|
|
197
126
|
|
|
198
|
-
errors[key] = result.error
|
|
127
|
+
errors[key] = result.error
|
|
199
128
|
}
|
|
200
|
-
})
|
|
129
|
+
})
|
|
201
130
|
|
|
202
131
|
if (errors !== null) {
|
|
203
|
-
return err(merge(annotateObject(plainObj), errors))
|
|
132
|
+
return err(merge(annotateObject(plainObj), errors))
|
|
204
133
|
} else {
|
|
205
|
-
return ok(rv)
|
|
134
|
+
return ok(rv)
|
|
206
135
|
}
|
|
207
|
-
})
|
|
136
|
+
})
|
|
208
137
|
}
|
|
209
|
-
/**
|
|
210
|
-
* Similar to `dict()`, but returns the result as a `Map<string, T>` (an [ES6
|
|
211
|
-
* Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map))
|
|
212
|
-
* instead.
|
|
213
|
-
*/
|
|
214
138
|
|
|
215
139
|
export function mapping(decoder) {
|
|
216
140
|
return dict(decoder).transform(function (obj) {
|
|
217
|
-
return new Map(
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
})
|
|
223
|
-
}
|
|
141
|
+
return new Map(
|
|
142
|
+
Object.keys(obj).map(function (key) {
|
|
143
|
+
return [key, obj[key]]
|
|
144
|
+
})
|
|
145
|
+
)
|
|
146
|
+
})
|
|
147
|
+
}
|
package/lib/strings.js
CHANGED
|
@@ -1,101 +1,58 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict'
|
|
2
2
|
|
|
3
|
-
exports.__esModule = true
|
|
4
|
-
exports.nonEmptyString = exports.httpsUrl = exports.email = void 0
|
|
5
|
-
exports.regex = regex
|
|
6
|
-
exports.uuidv4 = exports.uuidv1 = exports.uuid = exports.url = exports.string = void 0
|
|
3
|
+
exports.__esModule = true
|
|
4
|
+
exports.nonEmptyString = exports.httpsUrl = exports.email = void 0
|
|
5
|
+
exports.regex = regex
|
|
6
|
+
exports.uuidv4 = exports.uuidv1 = exports.uuid = exports.url = exports.string = void 0
|
|
7
7
|
|
|
8
|
-
var _Decoder = require(
|
|
8
|
+
var _Decoder = require('../Decoder')
|
|
9
9
|
|
|
10
|
-
var _unions = require(
|
|
10
|
+
var _unions = require('./unions')
|
|
11
11
|
|
|
12
|
-
var _utilities = require(
|
|
12
|
+
var _utilities = require('./utilities')
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
* \1 - the scheme
|
|
16
|
-
* \2 - the username/password (optional)
|
|
17
|
-
* \3 - the host
|
|
18
|
-
* \4 - the port (optional)
|
|
19
|
-
* \5 - the path (optional)
|
|
20
|
-
*/
|
|
21
|
-
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]*)?)?$/;
|
|
22
|
-
/**
|
|
23
|
-
* Accepts and returns strings.
|
|
24
|
-
*/
|
|
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]*)?)?$/
|
|
25
15
|
|
|
26
16
|
var string = (0, _Decoder.define)(function (blob, ok, err) {
|
|
27
|
-
return typeof blob === 'string' ? ok(blob) : err('Must be string')
|
|
28
|
-
})
|
|
29
|
-
/**
|
|
30
|
-
* Like `string`, but will reject the empty string or strings containing only whitespace.
|
|
31
|
-
*/
|
|
17
|
+
return typeof blob === 'string' ? ok(blob) : err('Must be string')
|
|
18
|
+
})
|
|
32
19
|
|
|
33
|
-
exports.string = string
|
|
34
|
-
var nonEmptyString = regex(/\S/, 'Must be non-empty string')
|
|
35
|
-
/**
|
|
36
|
-
* Accepts and returns strings that match the given regular expression.
|
|
37
|
-
*/
|
|
20
|
+
exports.string = string
|
|
21
|
+
var nonEmptyString = regex(/\S/, 'Must be non-empty string')
|
|
38
22
|
|
|
39
|
-
exports.nonEmptyString = nonEmptyString
|
|
23
|
+
exports.nonEmptyString = nonEmptyString
|
|
40
24
|
|
|
41
25
|
function regex(regex, msg) {
|
|
42
26
|
return string.refine(function (s) {
|
|
43
|
-
return regex.test(s)
|
|
44
|
-
}, msg)
|
|
27
|
+
return regex.test(s)
|
|
28
|
+
}, msg)
|
|
45
29
|
}
|
|
46
|
-
/**
|
|
47
|
-
* Accepts and returns strings that are syntactically valid email addresses.
|
|
48
|
-
* (This will not mean that the email address actually exist.)
|
|
49
|
-
*/
|
|
50
30
|
|
|
31
|
+
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')
|
|
51
32
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
33
|
+
exports.email = email
|
|
34
|
+
var url = (0, _unions.either)(
|
|
35
|
+
regex(url_re, 'Must be URL').transform(function (value) {
|
|
36
|
+
return new URL(value)
|
|
37
|
+
}),
|
|
38
|
+
(0, _utilities.instanceOf)(URL)
|
|
39
|
+
)
|
|
57
40
|
|
|
58
|
-
exports.
|
|
59
|
-
var url = (0, _unions.either)(regex(url_re, 'Must be URL').transform(function (value) {
|
|
60
|
-
return new URL(value);
|
|
61
|
-
}), (0, _utilities.instanceOf)(URL));
|
|
62
|
-
/**
|
|
63
|
-
* Accepts strings that are valid URLs, but only HTTPS ones. Returns the value
|
|
64
|
-
* as a URL instance.
|
|
65
|
-
*/
|
|
66
|
-
|
|
67
|
-
exports.url = url;
|
|
41
|
+
exports.url = url
|
|
68
42
|
var httpsUrl = url.refine(function (value) {
|
|
69
|
-
return value.protocol === 'https:'
|
|
70
|
-
}, 'Must be an HTTPS URL')
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
exports.uuid = uuid;
|
|
86
|
-
var uuidv1 = // https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address)
|
|
87
|
-
uuid.refine(function (value) {
|
|
88
|
-
return value[14] === '1';
|
|
89
|
-
}, 'Must be uuidv1');
|
|
90
|
-
/**
|
|
91
|
-
* Like `uuid`, but only accepts
|
|
92
|
-
* [UUIDv4](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_%28random%29)
|
|
93
|
-
* strings.
|
|
94
|
-
*/
|
|
95
|
-
|
|
96
|
-
exports.uuidv1 = uuidv1;
|
|
97
|
-
var uuidv4 = // https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)
|
|
98
|
-
uuid.refine(function (value) {
|
|
99
|
-
return value[14] === '4';
|
|
100
|
-
}, 'Must be uuidv4');
|
|
101
|
-
exports.uuidv4 = uuidv4;
|
|
43
|
+
return value.protocol === 'https:'
|
|
44
|
+
}, 'Must be an HTTPS URL')
|
|
45
|
+
|
|
46
|
+
exports.httpsUrl = httpsUrl
|
|
47
|
+
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')
|
|
48
|
+
|
|
49
|
+
exports.uuid = uuid
|
|
50
|
+
var uuidv1 = uuid.refine(function (value) {
|
|
51
|
+
return value[14] === '1'
|
|
52
|
+
}, 'Must be uuidv1')
|
|
53
|
+
|
|
54
|
+
exports.uuidv1 = uuidv1
|
|
55
|
+
var uuidv4 = uuid.refine(function (value) {
|
|
56
|
+
return value[14] === '4'
|
|
57
|
+
}, 'Must be uuidv4')
|
|
58
|
+
exports.uuidv4 = uuidv4
|
package/lib/strings.mjs
CHANGED
|
@@ -1,82 +1,40 @@
|
|
|
1
|
-
import { define } from '../Decoder.mjs'
|
|
2
|
-
import { either } from './unions.mjs'
|
|
3
|
-
import { instanceOf } from './utilities.mjs'
|
|
1
|
+
import { define } from '../Decoder.mjs'
|
|
2
|
+
import { either } from './unions.mjs'
|
|
3
|
+
import { instanceOf } from './utilities.mjs'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
* \1 - the scheme
|
|
7
|
-
* \2 - the username/password (optional)
|
|
8
|
-
* \3 - the host
|
|
9
|
-
* \4 - the port (optional)
|
|
10
|
-
* \5 - the path (optional)
|
|
11
|
-
*/
|
|
12
|
-
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]*)?)?$/;
|
|
13
|
-
/**
|
|
14
|
-
* Accepts and returns strings.
|
|
15
|
-
*/
|
|
5
|
+
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]*)?)?$/
|
|
16
6
|
|
|
17
7
|
export var string = define(function (blob, ok, err) {
|
|
18
|
-
return typeof blob === 'string' ? ok(blob) : err('Must be string')
|
|
19
|
-
})
|
|
20
|
-
/**
|
|
21
|
-
* Like `string`, but will reject the empty string or strings containing only whitespace.
|
|
22
|
-
*/
|
|
8
|
+
return typeof blob === 'string' ? ok(blob) : err('Must be string')
|
|
9
|
+
})
|
|
23
10
|
|
|
24
|
-
export var nonEmptyString = regex(/\S/, 'Must be non-empty string')
|
|
25
|
-
/**
|
|
26
|
-
* Accepts and returns strings that match the given regular expression.
|
|
27
|
-
*/
|
|
11
|
+
export var nonEmptyString = regex(/\S/, 'Must be non-empty string')
|
|
28
12
|
|
|
29
13
|
export function regex(regex, msg) {
|
|
30
14
|
return string.refine(function (s) {
|
|
31
|
-
return regex.test(s)
|
|
32
|
-
}, msg)
|
|
15
|
+
return regex.test(s)
|
|
16
|
+
}, msg)
|
|
33
17
|
}
|
|
34
|
-
/**
|
|
35
|
-
* Accepts and returns strings that are syntactically valid email addresses.
|
|
36
|
-
* (This will not mean that the email address actually exist.)
|
|
37
|
-
*/
|
|
38
18
|
|
|
39
|
-
export var email = regex(
|
|
40
|
-
/^(([^<>()[\]\\.,;:\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');
|
|
41
|
-
/**
|
|
42
|
-
* Accepts strings that are valid URLs, returns the value as a URL instance.
|
|
43
|
-
*/
|
|
19
|
+
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
20
|
|
|
45
|
-
export var url = either(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
*/
|
|
21
|
+
export var url = either(
|
|
22
|
+
regex(url_re, 'Must be URL').transform(function (value) {
|
|
23
|
+
return new URL(value)
|
|
24
|
+
}),
|
|
25
|
+
instanceOf(URL)
|
|
26
|
+
)
|
|
52
27
|
|
|
53
28
|
export var httpsUrl = url.refine(function (value) {
|
|
54
|
-
return value.protocol === 'https:'
|
|
55
|
-
}, 'Must be an HTTPS URL')
|
|
56
|
-
/**
|
|
57
|
-
* Accepts strings that are valid
|
|
58
|
-
* [UUIDs](https://en.wikipedia.org/wiki/universally_unique_identifier)
|
|
59
|
-
* (universally unique identifier).
|
|
60
|
-
*/
|
|
29
|
+
return value.protocol === 'https:'
|
|
30
|
+
}, 'Must be an HTTPS URL')
|
|
61
31
|
|
|
62
|
-
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')
|
|
63
|
-
/**
|
|
64
|
-
* Like `uuid`, but only accepts
|
|
65
|
-
* [UUIDv1](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_%28date-time_and_MAC_address%29)
|
|
66
|
-
* strings.
|
|
67
|
-
*/
|
|
32
|
+
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')
|
|
68
33
|
|
|
69
|
-
export var uuidv1 =
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}, 'Must be uuidv1');
|
|
73
|
-
/**
|
|
74
|
-
* Like `uuid`, but only accepts
|
|
75
|
-
* [UUIDv4](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_%28random%29)
|
|
76
|
-
* strings.
|
|
77
|
-
*/
|
|
34
|
+
export var uuidv1 = uuid.refine(function (value) {
|
|
35
|
+
return value[14] === '1'
|
|
36
|
+
}, 'Must be uuidv1')
|
|
78
37
|
|
|
79
|
-
export var uuidv4 =
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}, 'Must be uuidv4');
|
|
38
|
+
export var uuidv4 = uuid.refine(function (value) {
|
|
39
|
+
return value[14] === '4'
|
|
40
|
+
}, 'Must be uuidv4')
|
package/lib/unions.d.ts
CHANGED
|
@@ -49,7 +49,7 @@ export function oneOf<T extends Scalar>(constants: readonly T[]): Decoder<T>;
|
|
|
49
49
|
* error messages and is more performant at runtime because it doesn't have to
|
|
50
50
|
* try all decoders one by one.
|
|
51
51
|
*/
|
|
52
|
-
export function taggedUnion<O extends
|
|
52
|
+
export function taggedUnion<O extends Record<string, Decoder<any>>>(
|
|
53
53
|
field: string,
|
|
54
54
|
mapping: O,
|
|
55
55
|
): Decoder<Values<{ [key in keyof O]: DecoderType<O[key]> }>>;
|