/
Argument.ts
133 lines (122 loc) · 4.45 KB
/
Argument.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
import { AliasPiece } from '@sapphire/pieces';
import type { Result } from '@sapphire/result';
import type { Awaitable } from '@sapphire/utilities';
import type { Message } from 'discord.js';
import type { ArgumentError } from '../errors/ArgumentError';
import { Args } from '../parsers/Args';
import type { MessageCommand } from './Command';
/**
* Defines a synchronous result of an {@link Argument}, check {@link Argument.AsyncResult} for the asynchronous version.
*/
export type ArgumentResult<T> = Result<T, ArgumentError<T>>;
/**
* Defines a synchronous or asynchronous result of an {@link Argument}, check {@link Argument.AsyncResult} for the asynchronous version.
*/
export type AwaitableArgumentResult<T> = Awaitable<ArgumentResult<T>>;
/**
* Defines an asynchronous result of an {@link Argument}, check {@link Argument.Result} for the synchronous version.
*/
export type AsyncArgumentResult<T> = Promise<ArgumentResult<T>>;
export interface IArgument<T> {
/**
* The name of the argument, this is used to make the identification of an argument easier.
*/
readonly name: string;
/**
* The method which is called when invoking the argument.
* @param parameter The string parameter to parse.
* @param context The context for the method call, contains the message, command, and other options.
*/
run(parameter: string, context: Argument.Context<T>): Argument.AwaitableResult<T>;
}
/**
* The base argument class. This class is abstract and is to be extended by subclasses implementing the methods. In
* Sapphire's workflow, arguments are called when using {@link Args}'s methods (usually used inside {@link Command}s by default).
*
* @example
* ```typescript
* // TypeScript:
* import { Argument, PieceContext } from '@sapphire/framework';
* import { URL } from 'node:url';
*
* // Define a class extending `Argument`, then export it.
* // NOTE: You can use `export default` or `export =` too.
* export class CoreArgument extends Argument<URL> {
* public constructor(context: PieceContext) {
* super(context, { name: 'hyperlink', aliases: ['url'] });
* }
*
* public run(argument: string): Argument.Result<URL> {
* try {
* return this.ok(new URL(argument));
* } catch {
* return this.error(argument, 'ArgumentHyperlinkInvalidURL', 'The argument did not resolve to a valid URL.');
* }
* }
* }
*
* // Augment the ArgType structure so `args.pick('url')`, `args.repeat('url')`
* // and others have a return type of `URL`.
* declare module '@sapphire/framework' {
* export interface ArgType {
* url: URL;
* }
* }
* ```
*
* @example
* ```javascript
* // JavaScript:
* const { Argument } = require('@sapphire/framework');
*
* // Define a class extending `Argument`, then export it.
* module.exports = class CoreArgument extends Argument {
* constructor(context) {
* super(context, { name: 'hyperlink', aliases: ['url'] });
* }
*
* run(argument) {
* try {
* return this.ok(new URL(argument));
* } catch {
* return this.error(argument, 'ArgumentHyperlinkInvalidURL', 'The argument did not resolve to a valid URL.');
* }
* }
* }
* ```
*/
export abstract class Argument<T = unknown, O extends Argument.Options = Argument.Options> extends AliasPiece<O> implements IArgument<T> {
public abstract run(parameter: string, context: Argument.Context<T>): Argument.AwaitableResult<T>;
/**
* Wraps a value into a successful value.
* @param value The value to wrap.
*/
public ok(value: T): Argument.Result<T> {
return Args.ok(value);
}
/**
* Constructs an {@link Err} result containing an {@link ArgumentError} with a custom type.
* @param options The options to pass to the ArgumentError.
*/
public error(options: Omit<ArgumentError.Options<T>, 'argument'>): Argument.Result<T> {
return Args.error({ argument: this, identifier: this.name, ...options });
}
}
export interface ArgumentOptions extends AliasPiece.Options {}
export interface ArgumentContext<T = unknown> extends Record<PropertyKey, unknown> {
argument: IArgument<T>;
args: Args;
message: Message;
command: MessageCommand;
commandContext: MessageCommand.RunContext;
minimum?: number;
maximum?: number;
inclusive?: boolean;
}
export namespace Argument {
export type Options = ArgumentOptions;
export type Context<T = unknown> = ArgumentContext<T>;
export type Result<T> = ArgumentResult<T>;
export type AwaitableResult<T> = AwaitableArgumentResult<T>;
export type AsyncResult<T> = AsyncArgumentResult<T>;
}