Skip to main content

Creating your own arguments

Creating an argument can be done by extending the Argument class which can be imported from the framework:

const { isTextBasedChannel } = require('@sapphire/discord.js-utilities');
const { Argument, Resolvers } = require('@sapphire/framework');
const { isNullish } = require('@sapphire/utilities');

class TextBasedChannelsArgument extends Argument {
run(parameter, context) {
const { value } = Resolvers.resolveGuildChannel(parameter, context.message.guild);

if (!isNullish(value) && isTextBasedChannel(value)) {
return this.ok(value);
}

return this.error({
context,
parameter,
message: 'The provided argument could not be resolved to a text based channel.',
identifier: 'ChannelNotATextBasedChannel'
});
}
}
module.exports = {
TextBasedChannelsArgument
};

Typescript

Typescript users must augment Sapphire's ArgType interface, which is needed to increase the security of Sapphire's types. Otherwise, you will run into type errors in the next section.

info

Make sure you first create an index.d.ts file in the TypeScript root directory (that is to say, the directory you have configured as rootDir in your tsconfig, generally this is src. Note that we are NOT talking about the actual root folder here!) of your project, then put the following code using the name of your new argument, in this case textBasedChannels.

declare module '@sapphire/framework' {
interface ArgType {
textBasedChannels: string;
}
}

export default undefined;

The above code creates an argument which checks if the provided parameter is a valid text based channel. It first tries to resolve the parameter to a channel in the guild, if the the parameter is a valid channel, and the channel is a text based channel, it returns the value. If the channel is not a text based channel, or the parameter could not be resolved to a channel, it returns an error.

We then augment the @sapphire/framework module to include the new argument in the ArgType interface.

Passing custom options in one of the args methods:

If you want to pass a custom option, like an array to the argument context, to create an argument which checks if the parameter includes one of the elements from the array. You can add a context option to the argument. In your argument file:

const { Argument } = require('@sapphire/framework');
const { isNullishOrEmpty } = require('@sapphire/utilities');

class ArrayArgument extends Argument {
run(parameter, context) {
if (isNullishOrEmpty(context.array)) {
return this.error({
context,
parameter,
message: 'No array of options was provided. You should alert the bot developer.',
identifier: 'NoArrayContextProvided'
});
}

if (context.array.includes(parameter)) return this.ok(parameter);

return this.error({
context,
parameter,
message: 'The provided parameter does not include an element from the array.',
identifier: 'NotInArrayOfOptions'
});
}
}
module.exports = {
ArrayArgument
};
declare module '@sapphire/framework' {
interface ArgType {
array: string;
}
}

export default undefined;
info

This is essentially the enum argument, one of the Built-in arguments, which was added in version 2.3.0 of @sapphire/framework

The above code checks if the array passed in the context includes the parameter, if it does it returns the value, if not, an error is thrown. After that, we augment the @sapphire/framework module to include the new argument in the ArgType interface (as above).

With all that setup done, you can use the new argument in your command file:

const { Command } = require('@sapphire/framework');

class ArrayCommand extends Command {
async messageRun(message, args) {
const parameter = await args.pick('array', { array: ['yes', 'no'] });

return message.reply(`Your parameter ${parameter} is valid!`);
}
}
module.exports = {
ArrayCommand
};

The above code calls the pick method of the args class, specifies the argument name, which is 'array', and passes the array, which is your array you want to check from, in the context.

Using Args.make

Another way to create an argument is by using the make method of the Args class:

const { Args, Command } = require('@sapphire/framework');
const { isNullishOrEmpty } = require('@sapphire/utilities');

class SampleCommand extends Command {
async messageRun(message, args) {
const parameter = await args.pick(SampleCommand.numberOrString);

return message.reply(`Your parameter ${parameter} is a valid number or a string!`);
}

static numberOrString = Args.make((parameter, { argument }) => {
if (Number(parameter) || !isNullishOrEmpty(parameter)) {
return Args.ok(parameter);
}

return Args.error({
argument,
parameter,
identifier: 'NumberOrStringError',
message: 'The provided argument was neither a number nor a string.'
});
});
}
module.exports = {
SampleCommand
};

The above code creates a command, which picks a numberOrString argument from the provided text, the numberOrString argument is created below using the Args.make method, which takes the parameter, checks if it is a number and is not nullish or empty and returns the value. If not, an error is returned.