-
-
Notifications
You must be signed in to change notification settings - Fork 5
/
util.ts
144 lines (134 loc) 路 3.75 KB
/
util.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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import type { Predicate } from "./is.ts";
export type AssertMessageFactory = (
x: unknown,
pred: Predicate<unknown>,
name?: string,
) => string;
export const defaultAssertMessageFactory: AssertMessageFactory = (
x,
pred,
name,
) => {
const p = pred.name || "anonymous predicate";
const t = typeof x;
const v = JSON.stringify(x, null, 2);
return `Expected ${
name ?? "a value"
} that satisfies the predicate ${p}, got ${t}: ${v}`;
};
let assertMessageFactory = defaultAssertMessageFactory;
/**
* Represents an error that occurs when an assertion fails.
*/
export class AssertError extends Error {
/**
* Constructs a new `AssertError` instance.
* @param message The error message.
*/
constructor(message?: string) {
super(message);
if (Error.captureStackTrace) {
Error.captureStackTrace(this, AssertError);
}
this.name = this.constructor.name;
}
}
/**
* Sets the factory function used to generate assertion error messages.
* @param factory The factory function.
* @example
* ```ts
* import { setAssertMessageFactory } from "./util.ts";
* import is from "./is.ts";
*
* setAssertMessageFactory((x, pred) => {
* if (pred === is.String) {
* return `Expected a string, got ${typeof x}`;
* } else if (pred === is.Number) {
* return `Expected a number, got ${typeof x}`;
* } else if (pred === is.Boolean) {
* return `Expected a boolean, got ${typeof x}`;
* } else {
* return `Expected a value that satisfies the predicate, got ${typeof x}`;
* }
* });
* ```
*/
export function setAssertMessageFactory(factory: AssertMessageFactory): void {
assertMessageFactory = factory;
}
/**
* Asserts that the given value satisfies the provided predicate.
*
* ```ts
* import { assert } from "./util.ts";
* import is from "./is.ts";
*
* const a: unknown = "hello";
* assert(a, is.String);
* // a is now narrowed to string
* ```
*
* @param x The value to be asserted.
* @param pred The predicate function to test the value against.
* @param options Optional configuration for the assertion.
* @returns Nothing. The function has a return type of `asserts x is T` to help TypeScript narrow down the type of `x` after the assertion.
* @throws {AssertError} If the value does not satisfy the predicate.
*/
export function assert<T>(
x: unknown,
pred: Predicate<T>,
options: { message?: string; name?: string } = {},
): asserts x is T {
if (!pred(x)) {
throw new AssertError(
options.message ?? assertMessageFactory(x, pred, options.name),
);
}
}
/**
* Ensures that the given value satisfies the provided predicate.
*
* ```ts
* import { ensure } from "./util.ts";
* import is from "./is.ts";
*
* const a: unknown = "hello";
* const _: string = ensure(a, is.String);
* ```
*
* @param x The value to be ensured.
* @param pred The predicate function to test the value against.
* @param options Optional configuration for the assertion.
* @returns The input value `x`.
* @throws {AssertError} If the value does not satisfy the predicate.
*/
export function ensure<T>(
x: unknown,
pred: Predicate<T>,
options: { message?: string; name?: string } = {},
): T {
assert(x, pred, options);
return x;
}
/**
* Returns the input value if it satisfies the provided predicate, or `undefined` otherwise.
*
* ```ts
* import { maybe } from "./util.ts";
* import is from "./is.ts";
*
* const a: unknown = "hello";
* const _: string = maybe(a, is.String) ?? "default value";
* ```
*
* @param x The value to be tested.
* @param pred The predicate function to test the value against.
* @returns The input value `x` if it satisfies the predicate, or `undefined` otherwise.
*/
export function maybe<T>(
x: unknown,
pred: Predicate<T>,
): T | undefined {
return pred(x) ? x : undefined;
}