Skip to content

Commit

Permalink
Merge pull request #63 from thenorthsolution:flags
Browse files Browse the repository at this point in the history
Message Command Flags
  • Loading branch information
catplvsplus authored Aug 4, 2024
2 parents 7931a4d + d228109 commit 41ad32d
Show file tree
Hide file tree
Showing 22 changed files with 817 additions and 26 deletions.
29 changes: 29 additions & 0 deletions example/modules/Commands/Flags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// @ts-check
import { MessageCommandBuilder } from "reciple";
import { createMessageCommandUsage } from '@reciple/message-command-utils';

export class Message {
commands = [
new MessageCommandBuilder()
.setName('flag')
.setDescription('Sends a message')
.addFlag(flag => flag
.setName('flag')
.setDescription('A flag')
.setValueType('string')
.setRequired(true)
.setMandatory(true)
)
.setExecute(async ({ message, flags }) => {
await message.reply(flags.getFlagValues('flag', { required: true, type: 'string' })[0]);
})
];

onStart() {
logger.log(this.commands[0])
logger.log(createMessageCommandUsage(this.commands[0]))
return true;
}
}

export default new Message()
1 change: 0 additions & 1 deletion example/modules/Commands/Say.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// @ts-check

import { SlashCommandBuilder } from 'reciple';

/**
Expand Down
15 changes: 12 additions & 3 deletions example/modules/Halts/MessageCommandArguments.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ export class MessageCommandArguments {
* @param {import('reciple').MessageCommandHaltTriggerData} data
*/
async messageCommandHalt(data) {
if (data.reason !== CommandHaltReason.InvalidArguments && data.reason !== CommandHaltReason.MissingArguments) return;
console.log(data.executeData.options.invalidOptions);
console.log(data.executeData.options.missingOptions);
if (
data.reason !== CommandHaltReason.InvalidArguments &&
data.reason !== CommandHaltReason.MissingArguments &&
data.reason !== CommandHaltReason.InvalidFlags &&
data.reason !== CommandHaltReason.MissingFlags
) return;

switch (data.reason) {
case CommandHaltReason.InvalidArguments:
Expand All @@ -24,6 +27,12 @@ export class MessageCommandArguments {
case CommandHaltReason.MissingArguments:
await data.executeData.message.reply(`## Missing arguments\n${data.executeData.options.missingOptions.map(o => `- ${inlineCode(o.name)}`).join('\n')}`);
break;
case CommandHaltReason.InvalidFlags:
await data.executeData.message.reply(`## Invalid flags\n${data.executeData.flags.invalidFlags.map(o => `- ${inlineCode(o.name)} ${o.error?.message ?? 'Invalid value'}`).join('\n')}`);
break;
case CommandHaltReason.MissingFlags:
await data.executeData.message.reply(`## Missing flags\n${data.executeData.flags.missingFlags.map(o => `- ${inlineCode(o.name)}`).join('\n')}`);
break;
}

return true;
Expand Down
1 change: 0 additions & 1 deletion example/modules/Preconditions/MyPrecondition.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// @ts-check

/**
* @satisfies {import("reciple").CommandPreconditionData}
*/
Expand Down
2 changes: 1 addition & 1 deletion example/nodemon.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"node_modules/**"
],
"watch": [
"src",
"modules",
"reciple.mjs",
".env"
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export class ContextMenuCommandBuilder extends Mixin(DiscordJsContextMenuCommand
}

public static resolve(data: ContextMenuCommandResolvable): ContextMenuCommandBuilder {
return data instanceof ContextMenuCommandBuilder ? data : this.from(data);
return data instanceof ContextMenuCommandBuilder ? data : ContextMenuCommandBuilder.from(data);
}

public static async execute({ client, interaction, command }: ContextMenuCommandExecuteOptions): Promise<ContextMenuCommandExecuteData|null> {
Expand Down
132 changes: 126 additions & 6 deletions packages/core/src/classes/builders/MessageCommandBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@ import type { RecipleClient } from '../structures/RecipleClient.js';
import { RecipleError } from '../structures/RecipleError.js';
import type { CooldownData } from '../structures/Cooldown.js';
import { getCommand } from 'fallout-utility/commands';
import { parseArgs } from 'util';
import { MessageCommandFlagBuilder, type MessageCommandFlagResolvable } from './MessageCommandFlagBuilder.js';
import { MessageCommandFlagValidators } from '../validators/MessageCommandFlagValidator.js';
import { MessageCommandFlagManager } from '../managers/MessageCommandFlagManager.js';

export interface MessageCommandExecuteData {
type: CommandType.MessageCommand;
client: RecipleClient<true>;
message: Message<boolean>;
parserData: CommandData;
options: MessageCommandOptionManager;
flags: MessageCommandFlagManager;
builder: MessageCommandBuilder;
}

Expand Down Expand Up @@ -47,6 +52,11 @@ export interface MessageCommandBuilderData extends BaseCommandBuilderData {
* @default true
*/
validate_options?: boolean;
/**
* Whether to validate flags or not.
* @default true
*/
validate_flags?: boolean;
/**
* Allows commands to be executed in DMs.
* @default false
Expand All @@ -61,6 +71,10 @@ export interface MessageCommandBuilderData extends BaseCommandBuilderData {
* The options of the command.
*/
options?: MessageCommandOptionResolvable[];
/**
* The flags of the command.
*/
flags?: MessageCommandFlagResolvable[];
}

export interface MessageCommandBuilder extends BaseCommandBuilder {
Expand All @@ -77,9 +91,11 @@ export class MessageCommandBuilder extends BaseCommandBuilder implements Message
public description: string = '';
public aliases: string[] = [];
public validate_options: boolean = true;
public validate_flags: boolean = true;
public dm_permission: boolean = false;
public allow_bot: boolean = false;
public options: MessageCommandOptionBuilder[] = [];
public flags: MessageCommandFlagBuilder[] = [];

constructor(data?: Omit<Partial<MessageCommandBuilderData>, 'command_type'>) {
super(data);
Expand All @@ -88,9 +104,11 @@ export class MessageCommandBuilder extends BaseCommandBuilder implements Message
if (data?.description) this.setDescription(data.description);
if (data?.aliases) this.setAliases(data.aliases);
if (data?.validate_options) this.setValidateOptions(data.validate_options);
if (data?.validate_flags) this.setValidateFlags(data.validate_flags);
if (data?.dm_permission) this.setDMPermission(data.dm_permission);
if (data?.allow_bot) this.setAllowBot(data.allow_bot);
if (data?.options) this.setOptions(data.options);
if (data?.flags) this.setFlags(data.flags);
}

/**
Expand Down Expand Up @@ -145,6 +163,16 @@ export class MessageCommandBuilder extends BaseCommandBuilder implements Message
return this;
}

/**
* Set whether to validate flags or not.
* @param enabled Enable flag validation.
*/
public setValidateFlags(enabled: boolean): this {
MessageCommandValidators.isValidValidateFlags(enabled);
this.validate_flags = enabled;
return this;
}

/**
* Sets whether the command is available in DMs or not.
* @param DMPermission Enable command in Dms.
Expand All @@ -170,7 +198,7 @@ export class MessageCommandBuilder extends BaseCommandBuilder implements Message
* @param option Option data or builder.
*/
public addOption(option: MessageCommandOptionResolvable|((builder: MessageCommandOptionBuilder) => MessageCommandOptionBuilder)): this {
const opt = typeof option === 'function' ? option(new MessageCommandOptionBuilder()) : MessageCommandOptionBuilder.from(option);
const opt = typeof option === 'function' ? option(new MessageCommandOptionBuilder()) : MessageCommandOptionBuilder.resolve(option);
MessageCommandOptionValidators.isValidMessageCommandOptionResolvable(opt);

if (this.options.find(o => o.name === opt.name)) throw new RecipleError('An option with name "' + opt.name + '" already exists.');
Expand All @@ -196,6 +224,36 @@ export class MessageCommandBuilder extends BaseCommandBuilder implements Message
return this;
}

/**
* Adds new flag to the command.
* @param option Flag data or builder.
*/
public addFlag(option: MessageCommandFlagResolvable|((builder: MessageCommandFlagBuilder) => MessageCommandFlagBuilder)): this {
const opt = typeof option === 'function' ? option(new MessageCommandFlagBuilder()) : MessageCommandFlagBuilder.resolve(option);
MessageCommandFlagValidators.isValidMessageCommandFlagResolvable(opt);

if (this.flags.find(o => o.name === opt.name)) throw new RecipleError('A flag with name "' + opt.name + '" already exists.');

this.flags.push(MessageCommandFlagBuilder.resolve(opt));
return this;
}

/**
* Sets the flags of the command.
* @param flags Flags data or builders.
*/
public setFlags(...flags: RestOrArray<MessageCommandFlagResolvable|((builder: MessageCommandFlagBuilder) => MessageCommandFlagBuilder)>): this {
flags = normalizeArray(flags);
MessageCommandValidators.isValidFlags(flags);
this.flags = [];

for (const flag of flags) {
this.addFlag(flag);
}

return this;
}

public toJSON(): MessageCommandBuilderData {
return {
name: this.name,
Expand All @@ -204,7 +262,8 @@ export class MessageCommandBuilder extends BaseCommandBuilder implements Message
validate_options: this.validate_options,
dm_permission: this.dm_permission,
allow_bot: this.allow_bot,
options: this.options,
options: this.options.map(b => b.toJSON()),
flags: this.flags.map(b => b.toJSON()),
...super._toJSON<CommandType.MessageCommand, MessageCommandExecuteFunction>()
};
}
Expand All @@ -214,20 +273,53 @@ export class MessageCommandBuilder extends BaseCommandBuilder implements Message
}

public static resolve(data: MessageCommandResolvable): MessageCommandBuilder {
return data instanceof MessageCommandBuilder ? data : this.from(data);
return data instanceof MessageCommandBuilder ? data : MessageCommandBuilder.from(data);
}

public static async execute({ client, message, command }: MessageCommandExecuteOptions): Promise<MessageCommandExecuteData|null> {
if (!message.content) return null;

const prefix = typeof client.config.commands?.messageCommand?.prefix === 'function' ? await Promise.resolve(client.config.commands.messageCommand.prefix({ client, message, guild: message.guild, command })) : client.config.commands?.messageCommand?.prefix;
const separator = typeof client.config.commands?.messageCommand?.commandArgumentSeparator === 'function' ? await Promise.resolve(client.config.commands.messageCommand.commandArgumentSeparator({ client, message, guild: message.guild, command })) : client.config.commands?.messageCommand?.commandArgumentSeparator;
const parserData = getCommand(message.content, prefix, separator);
if (!parserData || !parserData.name) return null;
const commandData = getCommand(message.content, prefix, separator);
if (!commandData || !commandData.name) return null;

const builder = command ? this.resolve(command) : client.commands.get(parserData.name, CommandType.MessageCommand);
const builder = command ? this.resolve(command) : client.commands.get(commandData.name, CommandType.MessageCommand);
if (!builder) return null;

const { positionals: args, values: flags } = parseArgs({
args: commandData.args,
allowPositionals: true,
strict: false,
options: Object.fromEntries(
builder.flags
.map((o) => [
o.name,
Object.fromEntries(
Object.entries({
type: o.value_type ?? 'string',
multiple: o.multiple,
short: o.short,
default: o.multiple ? o.default_values : o.default_values?.[0],
})
.filter(([key, value]) => value !== undefined)
) as any
])
),
});

const parserData = {
...commandData as CommandData & { name: string; },
args,
flags: Object
.entries(flags)
.filter(([key, value]) => value !== undefined)
.map(([key, value]) => ({
name: key,
value: Array.isArray(value) ? value : [value] as (string|boolean)[],
}))
};

const executeData: MessageCommandExecuteData = {
type: builder.command_type,
client,
Expand All @@ -239,6 +331,12 @@ export class MessageCommandBuilder extends BaseCommandBuilder implements Message
message,
parserData,
client
}),
flags: await MessageCommandFlagManager.parseFlags({
command: builder,
message,
parserData,
client
})
};

Expand Down Expand Up @@ -295,6 +393,28 @@ export class MessageCommandBuilder extends BaseCommandBuilder implements Message
}
}

if (builder.validate_flags) {
if (executeData.flags.hasInvalidFlags) {
await client.commands.executeHalts({
commandType: builder.command_type,
reason: CommandHaltReason.InvalidFlags,
executeData,
invalidFlags: executeData.flags.invalidFlags
});
return null;
}

if (executeData.flags.hasMissingFlags) {
await client.commands.executeHalts({
commandType: builder.command_type,
reason: CommandHaltReason.MissingFlags,
executeData,
missingFlags: executeData.flags.missingFlags
});
return null;
}
}

return (await client.commands.executeCommandBuilderExecute(executeData)) ? executeData : null;
}
}
Expand Down
Loading

0 comments on commit 41ad32d

Please sign in to comment.