aboutsummaryrefslogtreecommitdiff
path: root/lib/utils/Arg.ts
blob: 99060fb6986e7cc2f1c45a7b177ffc575ece1638 (plain)
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
import {
	type BaseBotArgumentType,
	type BotArgumentType,
	type BotArgumentTypeCaster,
	type CommandMessage,
	type SlashMessage
} from '#lib';
import { Argument, type Command, type Flag, type ParsedValuePredicate } from 'discord-akairo';
import { type Message } from 'discord.js';

/**
 * Casts a phrase to this argument's type.
 * @param type - The type to cast to.
 * @param message - Message that called the command.
 * @param phrase - Phrase to process.
 */
export async function cast<T extends ATC>(type: T, message: CommandMessage | SlashMessage, phrase: string): Promise<ATCR<T>>;
export async function cast<T extends KBAT>(type: T, message: CommandMessage | SlashMessage, phrase: string): Promise<BAT[T]>;
export async function cast(type: AT | ATC, message: CommandMessage | SlashMessage, phrase: string): Promise<any>;
export async function cast(
	this: ThisType<Command>,
	type: ATC | AT,
	message: CommandMessage | SlashMessage,
	phrase: string
): Promise<any> {
	return Argument.cast.call(this, type as any, message.client.commandHandler.resolver, message as Message, phrase);
}

/**
 * Creates a type that is the left-to-right composition of the given types.
 * If any of the types fails, the entire composition fails.
 * @param types - Types to use.
 */
export function compose<T extends ATC>(...types: T[]): ATCATCR<T>;
export function compose<T extends KBAT>(...types: T[]): ATCBAT<T>;
export function compose(...types: (AT | ATC)[]): ATC;
export function compose(...types: (AT | ATC)[]): ATC {
	return Argument.compose(...(types as any));
}

/**
 * Creates a type that is the left-to-right composition of the given types.
 * If any of the types fails, the composition still continues with the failure passed on.
 * @param types - Types to use.
 */
export function composeWithFailure<T extends ATC>(...types: T[]): ATCATCR<T>;
export function composeWithFailure<T extends KBAT>(...types: T[]): ATCBAT<T>;
export function composeWithFailure(...types: (AT | ATC)[]): ATC;
export function composeWithFailure(...types: (AT | ATC)[]): ATC {
	return Argument.composeWithFailure(...(types as any));
}

/**
 * Checks if something is null, undefined, or a fail flag.
 * @param value - Value to check.
 */
export function isFailure(value: any): value is null | undefined | (Flag & { value: any }) {
	return Argument.isFailure(value);
}

/**
 * Creates a type from multiple types (product type).
 * Only inputs where each type resolves with a non-void value are valid.
 * @param types - Types to use.
 */
export function product<T extends ATC>(...types: T[]): ATCATCR<T>;
export function product<T extends KBAT>(...types: T[]): ATCBAT<T>;
export function product(...types: (AT | ATC)[]): ATC;
export function product(...types: (AT | ATC)[]): ATC {
	return Argument.product(...(types as any));
}

/**
 * Creates a type where the parsed value must be within a range.
 * @param type - The type to use.
 * @param min - Minimum value.
 * @param max - Maximum value.
 * @param inclusive - Whether or not to be inclusive on the upper bound.
 */
export function range<T extends ATC>(type: T, min: number, max: number, inclusive?: boolean): ATCATCR<T>;
export function range<T extends KBAT>(type: T, min: number, max: number, inclusive?: boolean): ATCBAT<T>;
export function range(type: AT | ATC, min: number, max: number, inclusive?: boolean): ATC;
export function range(type: AT | ATC, min: number, max: number, inclusive?: boolean): ATC {
	return Argument.range(type as any, min, max, inclusive);
}

/**
 * Creates a type that parses as normal but also tags it with some data.
 * Result is in an object `{ tag, value }` and wrapped in `Flag.fail` when failed.
 * @param type - The type to use.
 * @param tag - Tag to add. Defaults to the `type` argument, so useful if it is a string.
 */
export function tagged<T extends ATC>(type: T, tag?: any): ATCATCR<T>;
export function tagged<T extends KBAT>(type: T, tag?: any): ATCBAT<T>;
export function tagged(type: AT | ATC, tag?: any): ATC;
export function tagged(type: AT | ATC, tag?: any): ATC {
	return Argument.tagged(type as any, tag);
}

/**
 * Creates a type from multiple types (union type).
 * The first type that resolves to a non-void value is used.
 * Each type will also be tagged using `tagged` with themselves.
 * @param types - Types to use.
 */
export function taggedUnion<T extends ATC>(...types: T[]): ATCATCR<T>;
export function taggedUnion<T extends KBAT>(...types: T[]): ATCBAT<T>;
export function taggedUnion(...types: (AT | ATC)[]): ATC;
export function taggedUnion(...types: (AT | ATC)[]): ATC {
	return Argument.taggedUnion(...(types as any));
}

/**
 * Creates a type that parses as normal but also tags it with some data and carries the original input.
 * Result is in an object `{ tag, input, value }` and wrapped in `Flag.fail` when failed.
 * @param type - The type to use.
 * @param tag - Tag to add. Defaults to the `type` argument, so useful if it is a string.
 */
export function taggedWithInput<T extends ATC>(type: T, tag?: any): ATCATCR<T>;
export function taggedWithInput<T extends KBAT>(type: T, tag?: any): ATCBAT<T>;
export function taggedWithInput(type: AT | ATC, tag?: any): ATC;
export function taggedWithInput(type: AT | ATC, tag?: any): ATC {
	return Argument.taggedWithInput(type as any, tag);
}

/**
 * Creates a type from multiple types (union type).
 * The first type that resolves to a non-void value is used.
 * @param types - Types to use.
 */
export function union<T extends ATC>(...types: T[]): ATCATCR<T>;
export function union<T extends KBAT>(...types: T[]): ATCBAT<T>;
export function union(...types: (AT | ATC)[]): ATC;
export function union(...types: (AT | ATC)[]): ATC {
	return Argument.union(...(types as any));
}

/**
 * Creates a type with extra validation.
 * If the predicate is not true, the value is considered invalid.
 * @param type - The type to use.
 * @param predicate - The predicate function.
 */
export function validate<T extends ATC>(type: T, predicate: ParsedValuePredicate): ATCATCR<T>;
export function validate<T extends KBAT>(type: T, predicate: ParsedValuePredicate): ATCBAT<T>;
export function validate(type: AT | ATC, predicate: ParsedValuePredicate): ATC;
export function validate(type: AT | ATC, predicate: ParsedValuePredicate): ATC {
	return Argument.validate(type as any, predicate);
}

/**
 * Creates a type that parses as normal but also carries the original input.
 * Result is in an object `{ input, value }` and wrapped in `Flag.fail` when failed.
 * @param type - The type to use.
 */
export function withInput<T extends ATC>(type: T): ATC<ATCR<T>>;
export function withInput<T extends KBAT>(type: T): ATCBAT<T>;
export function withInput(type: AT | ATC): ATC;
export function withInput(type: AT | ATC): ATC {
	return Argument.withInput(type as any);
}

type CustomArgumentTypeCasterReturn<R> = R extends BotArgumentTypeCaster<infer S> ? S : R;
/** ```ts
 * <R = unknown> = CustomArgumentTypeCaster<R>
 * ``` */
type ATC<R = unknown> = BotArgumentTypeCaster<R>;
/** ```ts
 * keyof BaseCustomArgumentType
 * ``` */
type KBAT = keyof BaseBotArgumentType;
/** ```ts
 * <R> = CustomArgumentTypeCasterReturn<R>
 * ``` */
type ATCR<R> = CustomArgumentTypeCasterReturn<R>;
/** ```ts
 * CustomArgumentType
 * ``` */
type AT = BotArgumentType;
/** ```ts
 * BaseCustomArgumentType
 * ``` */
type BAT = BaseBotArgumentType;

/** ```ts
 * <T extends CustomArgumentTypeCaster> = CustomArgumentTypeCaster<CustomArgumentTypeCasterReturn<T>>
 * ``` */
type ATCATCR<T extends BotArgumentTypeCaster> = BotArgumentTypeCaster<CustomArgumentTypeCasterReturn<T>>;
/** ```ts
 * <T extends keyof BaseCustomArgumentType> = CustomArgumentTypeCaster<BaseCustomArgumentType[T]>
 * ``` */
type ATCBAT<T extends keyof BaseBotArgumentType> = BotArgumentTypeCaster<BaseBotArgumentType[T]>;