Skip to main content

Using flags

So far we have covered arguments, which are positional - i.e., the order of the arguments matters and they are parsed in the given order. But, what if we want to have a boolean argument that can appear anywhere after the command invocation? That's where flags come in.

Flags are likely familiar to people who have used UNIX-style command-line programs and are formatted as --flag in much the same way. For example, you'd use node --version to get the version of your NodeJS installation.

With Sapphire you can use flags in two ways: declarative and imperative.

tip

Flags are always boolean values

caution

If a flag is read via args.getFlags('<flagName>') but it is not provided by the user, it will default to false as it is not set.

Imperative Flags

Imperative flags are flags you specify in the command options, and using them means Sapphire will only parse the specified flags. We recommend this method because it can avoid unexpected situations where something, for example in args.rest('string'), is parsed as a flag mistakenly. An example of where this could go wrong is adding flags to an announcement command - the user will struggle if they attempt to use the flag as part of the announcement text because Sapphire will parse it as a flag instead of string content.

To add imperative flags to your command you specify them in your command's options, like so:

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

module.exports = class FlagsCommand extends Command {
constructor(context) {
super(context, {
flags: ['version', 'v']
});
}

async messageRun(message, args) {}
};
info

We only parse the specified flags when using imperative flags. If the user provides --anything --else --like --this, it'll be parsed as textual data rather than flags with this code, because we told Sapphire the only valid flags are --version and --v.

Next, to check the flags that were set we use args.getFlags('<flagName>')

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

module.exports = class FlagsCommand extends Command {
constructor(context) {
super(context, {
flags: ['version', 'v']
});
}

async messageRun(message, args) {
const firstArgument = await args.pick('string');
const isRequestingVersion = args.getFlags('version', 'v');
const secondArgument = await args.pick('string');
// ...
}
};
info

Unlike methods like [args.pick('<argumentName>')][pick] and args.rest, args.getFlags('<flagName>') isn't asynchronous, so it doesn't need to be awaited - it returns a regular boolean, rather than a promise.

Declarative Flags

If you use declarative flags, Sapphire will treat everything starting with 2 consecutive hyphens as a flag without validating against command options, meaning that --these --will --all --be --flags. This can lead to unexpected situations, especially when using args.rest('string'); however, it enables dynamic flag setting and it's easier for you as a developer because you don't need to keep track of all the valid flags.

The process of configuring declarative flags is similar to imperative flags, but instead of providing an array of flags, you just set flags to true, like so:

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

module.exports = class FlagsCommand extends Command {
constructor(context) {
super(context, {
flags: true
});
}

async messageRun(message, args) {
const firstArgument = await args.pick('string');
const isRequestingVersion = args.getFlags('version', 'v');
const secondArgument = await args.pick('string');
// ...
}
};