Suite of AT Protocol TypeScript libraries built on web standards
1import {
2 Schema,
3 type ValidationResult,
4 type ValidatorContext,
5} from "../validation.ts";
6
7export type IntegerSchemaOptions = {
8 default?: number;
9 minimum?: number;
10 maximum?: number;
11 enum?: readonly number[];
12 const?: number;
13};
14
15export class IntegerSchema<
16 const Options extends IntegerSchemaOptions = any,
17> extends Schema<number> {
18 constructor(readonly options: Options) {
19 super();
20 }
21
22 validateInContext(
23 input: unknown = this.options.default,
24 ctx: ValidatorContext,
25 ): ValidationResult<number> {
26 const int = coerceToInteger(input);
27 if (int == null) {
28 return ctx.issueInvalidType(input, "integer");
29 }
30
31 const { minimum } = this.options;
32 if (minimum != null && int < minimum) {
33 return ctx.issueTooSmall(int, "integer", minimum, int);
34 }
35
36 const { maximum } = this.options;
37 if (maximum != null && int > maximum) {
38 return ctx.issueTooBig(int, "integer", maximum, int);
39 }
40
41 const { enum: enumValues } = this.options;
42 if (enumValues != null && !enumValues.includes(int)) {
43 return ctx.issueInvalidValue(int, enumValues);
44 }
45
46 const { const: constValue } = this.options;
47 if (constValue !== undefined && int !== constValue) {
48 return ctx.issueInvalidValue(int, [constValue]);
49 }
50
51 return ctx.success(int);
52 }
53}
54
55function coerceToInteger(input: unknown): number | null {
56 switch (typeof input) {
57 case "number":
58 return Number.isInteger(input) ? input : null;
59 case "string": {
60 if (!/^-?\d+$/.test(input)) return null;
61 const n = Number(input);
62 return Number.isInteger(n) ? n : null;
63 }
64 default:
65 return null;
66 }
67}