-
Notifications
You must be signed in to change notification settings - Fork 5
/
stringAsInteger.ts
89 lines (76 loc) · 2.19 KB
/
stringAsInteger.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import { integerRuntype } from './integer'
import {
createFail,
failSymbol,
InternalRuntype,
isFail,
propagateFail,
Runtype,
setupInternalRuntype,
} from './runtype'
export const stringAsIntegerRuntype = setupInternalRuntype<number>(
(v, failOrThrow) => {
if (typeof v === 'string') {
const parsedNumber = parseInt(v, 10)
const n: number = (integerRuntype as InternalRuntype<any>)(
parsedNumber,
failSymbol,
)
if (isFail(n)) {
return propagateFail(failOrThrow, n, v)
}
// ensure that value did only contain that integer, nothing else
// but also make '+1' === '1' and '-0' === '0'
const vStringSansLeadingPlus =
v === '-0' ? '0' : v[0] === '+' ? v.slice(1) : v
if (n.toString() !== vStringSansLeadingPlus) {
return createFail(
failOrThrow,
'expected string to contain only the safe integer, not additional characters, whitespace or leading zeros',
v,
)
}
return n
}
return createFail(
failOrThrow,
'expected a string that contains a safe integer',
v,
)
},
)
/**
* A string that is parsed as an integer.
*
* Parsing is strict, e.g leading/trailing whitespace or leading zeros will
* result in an error. Exponential notation is not allowed. The resulting
* number must be a safe integer (`Number.isSafeInteger`).
* A leading '+' or '-' is allowed.
*
* Options:
*
* min .. reject numbers smaller than that
* max .. reject number larger than that
*/
export function stringAsInteger(options?: {
min?: number
max?: number
}): Runtype<number> {
if (!options) {
return stringAsIntegerRuntype
}
const { min, max } = options
return setupInternalRuntype<number>((v, failOrThrow) => {
const n = (stringAsIntegerRuntype as InternalRuntype<any>)(v, failOrThrow)
if (isFail(n)) {
return propagateFail(failOrThrow, n, v)
}
if (min !== undefined && n < min) {
return createFail(failOrThrow, `expected the integer to be >= ${min}`, v)
}
if (max !== undefined && n > max) {
return createFail(failOrThrow, `expected the integer to be <= ${max}`, v)
}
return n
})
}