@constructive-io/coerce 0.2.0 → 0.3.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/README.md +1 -0
- package/coerce.d.ts +20 -0
- package/coerce.js +40 -1
- package/esm/coerce.js +36 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -66,6 +66,7 @@ Then the text-carried and named shapes — what an env var, a query string or a
|
|
|
66
66
|
| `asIntegerIn` | `requireIntegerIn` | an integer within `{ min, max }`, inclusive |
|
|
67
67
|
| `asPort` | `requirePort` | a port: an integer in `1..65535`, from a number or a string |
|
|
68
68
|
| `asBigInt` | `requireBigInt` | a `bigint`, an integer, or a digit string |
|
|
69
|
+
| `asBigIntString` | `requireBigIntString` | the same, answered as canonical digits — the wire form of an `int8` |
|
|
69
70
|
| `asUrl` | `requireUrl` | an absolute URL — a scheme is required |
|
|
70
71
|
| `asHostname` | `requireHostname` | a hostname or IP address — no scheme, port or path |
|
|
71
72
|
| `asEmail` | `requireEmail` | an email address |
|
package/coerce.d.ts
CHANGED
|
@@ -48,6 +48,14 @@ export declare const asBoolean: (value: unknown) => boolean | null;
|
|
|
48
48
|
* shrinks.
|
|
49
49
|
*/
|
|
50
50
|
export declare const asStringArray: (value: unknown) => string[] | null;
|
|
51
|
+
/**
|
|
52
|
+
* An array whose every entry coerces through `element`, else `null`. One bad
|
|
53
|
+
* entry rejects the whole array — a partially-valid list is a partially-wrong
|
|
54
|
+
* answer.
|
|
55
|
+
*/
|
|
56
|
+
export declare const asArrayOf: <T>(value: unknown, element: (entry: unknown) => T | null) => T[] | null;
|
|
57
|
+
/** {@link asArrayOf}, throwing {@link CoerceError} when absent. */
|
|
58
|
+
export declare const requireArrayOf: <T>(value: unknown, element: (entry: unknown) => T | null, label: string, expected?: string) => T[];
|
|
51
59
|
/**
|
|
52
60
|
* A list of non-empty strings from either an array (see
|
|
53
61
|
* {@link asStringArray}) or a delimited string, else `null`.
|
|
@@ -104,6 +112,16 @@ export declare const asPort: (value: unknown) => number | null;
|
|
|
104
112
|
* its way through JSON, where it cannot survive as a `number`.
|
|
105
113
|
*/
|
|
106
114
|
export declare const asBigInt: (value: unknown) => bigint | null;
|
|
115
|
+
/**
|
|
116
|
+
* A whole number in its canonical text form, else `null` — {@link asBigInt}
|
|
117
|
+
* spelled the way a 64-bit value travels.
|
|
118
|
+
*
|
|
119
|
+
* Text is the wire format for `int8`: node-postgres returns the type as a
|
|
120
|
+
* string, JSON carries it as one, and a `number` would silently lose identity
|
|
121
|
+
* past 2^53. Every accepted shape is normalised through `BigInt`, so `'007'`
|
|
122
|
+
* and `7` both answer `'7'` and two ids compare as themselves.
|
|
123
|
+
*/
|
|
124
|
+
export declare const asBigIntString: (value: unknown) => string | null;
|
|
107
125
|
/**
|
|
108
126
|
* An absolute URL, returned **verbatim**, else `null`. A scheme is required, so
|
|
109
127
|
* `'example.com'` — which is a path, and a classic way to fetch the wrong
|
|
@@ -163,6 +181,8 @@ export declare const requireNumericInteger: (value: unknown, label: string) => n
|
|
|
163
181
|
export declare const requirePort: (value: unknown, label: string) => number;
|
|
164
182
|
/** {@link asBigInt}, throwing {@link CoerceError} when absent. */
|
|
165
183
|
export declare const requireBigInt: (value: unknown, label: string) => bigint;
|
|
184
|
+
/** {@link asBigIntString}, throwing {@link CoerceError} when absent. */
|
|
185
|
+
export declare const requireBigIntString: (value: unknown, label: string) => string;
|
|
166
186
|
/** {@link asUrl}, throwing {@link CoerceError} when absent. */
|
|
167
187
|
export declare const requireUrl: (value: unknown, label: string) => string;
|
|
168
188
|
/** {@link asHostname}, throwing {@link CoerceError} when absent. */
|
package/coerce.js
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* which keeps this package usable off the request path.
|
|
23
23
|
*/
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.requireOneOf = exports.asOneOf = exports.requireIntegerIn = exports.requireNumberIn = exports.requireJson = exports.requireDuration = exports.requireUuid = exports.requireEmail = exports.requireHostname = exports.requireUrl = exports.requireBigInt = exports.requirePort = exports.requireNumericInteger = exports.requireNumeric = exports.requireIsoString = exports.requireDate = exports.requireRecord = exports.requireStringList = exports.requireStringArray = exports.requireBoolean = exports.requireInteger = exports.requireNumber = exports.requireString = exports.asJson = exports.asDuration = exports.asUuid = exports.asEmail = exports.asHostname = exports.asUrl = exports.asBigInt = exports.asPort = exports.asIntegerIn = exports.asNumberIn = exports.asNumericInteger = exports.asNumeric = exports.asIsoString = exports.asDate = exports.asRecord = exports.asStringList = exports.asStringArray = exports.asBoolean = exports.asInteger = exports.asNumber = exports.asString = exports.CoerceError = void 0;
|
|
25
|
+
exports.requireOneOf = exports.asOneOf = exports.requireIntegerIn = exports.requireNumberIn = exports.requireJson = exports.requireDuration = exports.requireUuid = exports.requireEmail = exports.requireHostname = exports.requireUrl = exports.requireBigIntString = exports.requireBigInt = exports.requirePort = exports.requireNumericInteger = exports.requireNumeric = exports.requireIsoString = exports.requireDate = exports.requireRecord = exports.requireStringList = exports.requireStringArray = exports.requireBoolean = exports.requireInteger = exports.requireNumber = exports.requireString = exports.asJson = exports.asDuration = exports.asUuid = exports.asEmail = exports.asHostname = exports.asUrl = exports.asBigIntString = exports.asBigInt = exports.asPort = exports.asIntegerIn = exports.asNumberIn = exports.asNumericInteger = exports.asNumeric = exports.asIsoString = exports.asDate = exports.asRecord = exports.asStringList = exports.requireArrayOf = exports.asArrayOf = exports.asStringArray = exports.asBoolean = exports.asInteger = exports.asNumber = exports.asString = exports.CoerceError = void 0;
|
|
26
26
|
/** A value that was required but absent or of the wrong shape. */
|
|
27
27
|
class CoerceError extends Error {
|
|
28
28
|
/** What the caller was asking for, e.g. `'message_id'`. */
|
|
@@ -85,6 +85,32 @@ const asStringArray = (value) => {
|
|
|
85
85
|
return strings;
|
|
86
86
|
};
|
|
87
87
|
exports.asStringArray = asStringArray;
|
|
88
|
+
/**
|
|
89
|
+
* An array whose every entry coerces through `element`, else `null`. One bad
|
|
90
|
+
* entry rejects the whole array — a partially-valid list is a partially-wrong
|
|
91
|
+
* answer.
|
|
92
|
+
*/
|
|
93
|
+
const asArrayOf = (value, element) => {
|
|
94
|
+
if (!Array.isArray(value))
|
|
95
|
+
return null;
|
|
96
|
+
const entries = [];
|
|
97
|
+
for (const item of value) {
|
|
98
|
+
const coerced = element(item);
|
|
99
|
+
if (coerced === null)
|
|
100
|
+
return null;
|
|
101
|
+
entries.push(coerced);
|
|
102
|
+
}
|
|
103
|
+
return entries;
|
|
104
|
+
};
|
|
105
|
+
exports.asArrayOf = asArrayOf;
|
|
106
|
+
/** {@link asArrayOf}, throwing {@link CoerceError} when absent. */
|
|
107
|
+
const requireArrayOf = (value, element, label, expected = 'an array of valid entries') => {
|
|
108
|
+
const entries = (0, exports.asArrayOf)(value, element);
|
|
109
|
+
if (entries === null)
|
|
110
|
+
throw new CoerceError(label, expected);
|
|
111
|
+
return entries;
|
|
112
|
+
};
|
|
113
|
+
exports.requireArrayOf = requireArrayOf;
|
|
88
114
|
/**
|
|
89
115
|
* A list of non-empty strings from either an array (see
|
|
90
116
|
* {@link asStringArray}) or a delimited string, else `null`.
|
|
@@ -183,6 +209,17 @@ const asBigInt = (value) => {
|
|
|
183
209
|
};
|
|
184
210
|
exports.asBigInt = asBigInt;
|
|
185
211
|
const INTEGER_TEXT = /^[+-]?\d+$/;
|
|
212
|
+
/**
|
|
213
|
+
* A whole number in its canonical text form, else `null` — {@link asBigInt}
|
|
214
|
+
* spelled the way a 64-bit value travels.
|
|
215
|
+
*
|
|
216
|
+
* Text is the wire format for `int8`: node-postgres returns the type as a
|
|
217
|
+
* string, JSON carries it as one, and a `number` would silently lose identity
|
|
218
|
+
* past 2^53. Every accepted shape is normalised through `BigInt`, so `'007'`
|
|
219
|
+
* and `7` both answer `'7'` and two ids compare as themselves.
|
|
220
|
+
*/
|
|
221
|
+
const asBigIntString = (value) => (0, exports.asBigInt)(value)?.toString() ?? null;
|
|
222
|
+
exports.asBigIntString = asBigIntString;
|
|
186
223
|
/**
|
|
187
224
|
* An absolute URL, returned **verbatim**, else `null`. A scheme is required, so
|
|
188
225
|
* `'example.com'` — which is a path, and a classic way to fetch the wrong
|
|
@@ -316,6 +353,8 @@ exports.requireNumericInteger = require_(exports.asNumericInteger, 'an integer')
|
|
|
316
353
|
exports.requirePort = require_(exports.asPort, 'a port in 1..65535');
|
|
317
354
|
/** {@link asBigInt}, throwing {@link CoerceError} when absent. */
|
|
318
355
|
exports.requireBigInt = require_(exports.asBigInt, 'a whole number');
|
|
356
|
+
/** {@link asBigIntString}, throwing {@link CoerceError} when absent. */
|
|
357
|
+
exports.requireBigIntString = require_(exports.asBigIntString, 'a whole number');
|
|
319
358
|
/** {@link asUrl}, throwing {@link CoerceError} when absent. */
|
|
320
359
|
exports.requireUrl = require_(exports.asUrl, 'an absolute URL');
|
|
321
360
|
/** {@link asHostname}, throwing {@link CoerceError} when absent. */
|
package/esm/coerce.js
CHANGED
|
@@ -76,6 +76,30 @@ export const asStringArray = (value) => {
|
|
|
76
76
|
}
|
|
77
77
|
return strings;
|
|
78
78
|
};
|
|
79
|
+
/**
|
|
80
|
+
* An array whose every entry coerces through `element`, else `null`. One bad
|
|
81
|
+
* entry rejects the whole array — a partially-valid list is a partially-wrong
|
|
82
|
+
* answer.
|
|
83
|
+
*/
|
|
84
|
+
export const asArrayOf = (value, element) => {
|
|
85
|
+
if (!Array.isArray(value))
|
|
86
|
+
return null;
|
|
87
|
+
const entries = [];
|
|
88
|
+
for (const item of value) {
|
|
89
|
+
const coerced = element(item);
|
|
90
|
+
if (coerced === null)
|
|
91
|
+
return null;
|
|
92
|
+
entries.push(coerced);
|
|
93
|
+
}
|
|
94
|
+
return entries;
|
|
95
|
+
};
|
|
96
|
+
/** {@link asArrayOf}, throwing {@link CoerceError} when absent. */
|
|
97
|
+
export const requireArrayOf = (value, element, label, expected = 'an array of valid entries') => {
|
|
98
|
+
const entries = asArrayOf(value, element);
|
|
99
|
+
if (entries === null)
|
|
100
|
+
throw new CoerceError(label, expected);
|
|
101
|
+
return entries;
|
|
102
|
+
};
|
|
79
103
|
/**
|
|
80
104
|
* A list of non-empty strings from either an array (see
|
|
81
105
|
* {@link asStringArray}) or a delimited string, else `null`.
|
|
@@ -164,6 +188,16 @@ export const asBigInt = (value) => {
|
|
|
164
188
|
return str !== undefined && INTEGER_TEXT.test(str) ? BigInt(str) : null;
|
|
165
189
|
};
|
|
166
190
|
const INTEGER_TEXT = /^[+-]?\d+$/;
|
|
191
|
+
/**
|
|
192
|
+
* A whole number in its canonical text form, else `null` — {@link asBigInt}
|
|
193
|
+
* spelled the way a 64-bit value travels.
|
|
194
|
+
*
|
|
195
|
+
* Text is the wire format for `int8`: node-postgres returns the type as a
|
|
196
|
+
* string, JSON carries it as one, and a `number` would silently lose identity
|
|
197
|
+
* past 2^53. Every accepted shape is normalised through `BigInt`, so `'007'`
|
|
198
|
+
* and `7` both answer `'7'` and two ids compare as themselves.
|
|
199
|
+
*/
|
|
200
|
+
export const asBigIntString = (value) => asBigInt(value)?.toString() ?? null;
|
|
167
201
|
/**
|
|
168
202
|
* An absolute URL, returned **verbatim**, else `null`. A scheme is required, so
|
|
169
203
|
* `'example.com'` — which is a path, and a classic way to fetch the wrong
|
|
@@ -291,6 +325,8 @@ export const requireNumericInteger = require_(asNumericInteger, 'an integer');
|
|
|
291
325
|
export const requirePort = require_(asPort, 'a port in 1..65535');
|
|
292
326
|
/** {@link asBigInt}, throwing {@link CoerceError} when absent. */
|
|
293
327
|
export const requireBigInt = require_(asBigInt, 'a whole number');
|
|
328
|
+
/** {@link asBigIntString}, throwing {@link CoerceError} when absent. */
|
|
329
|
+
export const requireBigIntString = require_(asBigIntString, 'a whole number');
|
|
294
330
|
/** {@link asUrl}, throwing {@link CoerceError} when absent. */
|
|
295
331
|
export const requireUrl = require_(asUrl, 'an absolute URL');
|
|
296
332
|
/** {@link asHostname}, throwing {@link CoerceError} when absent. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constructive-io/coerce",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"author": "Constructive <developers@constructive.io>",
|
|
5
5
|
"description": "Coerce untrusted unknown values into narrow TypeScript types",
|
|
6
6
|
"main": "index.js",
|
|
@@ -36,5 +36,5 @@
|
|
|
36
36
|
"validation",
|
|
37
37
|
"typescript"
|
|
38
38
|
],
|
|
39
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "ce544846eafd96280fac2607f873960392ae2c89"
|
|
40
40
|
}
|