A social knowledge tool for researchers built on ATProto
1export type GuardResponse = string; // This remains the type for the error message
2
3import { Result, ok, err } from './Result'; // Import ok and err factories
4
5export interface IGuardArgument {
6 argument: any;
7 argumentName: string;
8}
9
10export type GuardArgumentCollection = IGuardArgument[];
11
12// Define the specific Result type used by Guard functions
13// Success holds `void` (or `undefined`), Error holds the message string
14type GuardResult = Result<void, GuardResponse>;
15
16export class Guard {
17 // Combine function now expects GuardResult[] and returns GuardResult
18 public static combine(guardResults: GuardResult[]): GuardResult {
19 for (const result of guardResults) {
20 // Use the isErr type guard
21 if (result.isErr()) {
22 // Return the first error encountered
23 return result; // No need to cast, it's already Err<void, GuardResponse>
24 }
25 }
26 // If all results are Ok, return a single Ok
27 return ok(undefined); // Success case carries no value
28 }
29
30 public static greaterThan(
31 minValue: number,
32 actualValue: number,
33 ): GuardResult {
34 return actualValue > minValue
35 ? ok(undefined) // Use ok factory
36 : err(`Number given {${actualValue}} is not greater than {${minValue}}`); // Use err factory
37 }
38
39 public static againstAtLeast(numChars: number, text: string): GuardResult {
40 return text.length >= numChars
41 ? ok(undefined) // Use ok factory
42 : err(`Text is not at least ${numChars} chars.`); // Use err factory
43 }
44
45 public static againstAtMost(numChars: number, text: string): GuardResult {
46 return text.length <= numChars
47 ? ok(undefined) // Use ok factory
48 : err(`Text is greater than ${numChars} chars.`); // Use err factory
49 }
50
51 public static againstNullOrUndefined(
52 argument: any,
53 argumentName: string,
54 ): GuardResult {
55 if (argument === null || argument === undefined) {
56 return err(`${argumentName} is null or undefined`); // Use err factory
57 } else {
58 return ok(undefined); // Use ok factory
59 }
60 }
61
62 public static againstNullOrUndefinedBulk(
63 args: GuardArgumentCollection,
64 ): GuardResult {
65 for (const arg of args) {
66 const result = this.againstNullOrUndefined(
67 arg.argument,
68 arg.argumentName,
69 );
70 // Use the isErr type guard
71 if (result.isErr()) {
72 return result; // Return the Err result directly
73 }
74 }
75 // If loop completes, all arguments were valid
76 return ok(undefined); // Use ok factory
77 }
78
79 public static isOneOf(
80 value: any,
81 validValues: any[],
82 argumentName: string,
83 ): GuardResult {
84 let isValid = false;
85 for (const validValue of validValues) {
86 if (value === validValue) {
87 isValid = true;
88 }
89 }
90
91 if (isValid) {
92 return ok(undefined); // Use ok factory
93 } else {
94 // Use err factory
95 return err(
96 `${argumentName} isn't oneOf the correct types in ${JSON.stringify(
97 validValues,
98 )}. Got "${value}".`,
99 );
100 }
101 }
102
103 public static inRange(
104 num: number,
105 min: number,
106 max: number,
107 argumentName: string,
108 ): GuardResult {
109 const isInRange = num >= min && num <= max;
110 if (!isInRange) {
111 // Use err factory
112 return err(`${argumentName} is not within range ${min} to ${max}.`);
113 } else {
114 return ok(undefined); // Use ok factory
115 }
116 }
117
118 public static allInRange(
119 numbers: number[],
120 min: number,
121 max: number,
122 argumentName: string,
123 ): GuardResult {
124 for (const num of numbers) {
125 const numIsInRangeResult = this.inRange(num, min, max, argumentName);
126 // Use isErr type guard
127 if (numIsInRangeResult.isErr()) {
128 // Return the specific error from inRange
129 return err(
130 `${argumentName} is not within the range. Failed value: ${num}`,
131 ); // Or return numIsInRangeResult directly
132 }
133 }
134 // If loop completes, all numbers are in range
135 return ok(undefined); // Use ok factory
136 }
137}