diff --git a/src/events/command-handler/CorePreCommandRun.ts b/src/events/command-handler/CorePreCommandRun.ts index 9c22e3725..2f0927e9d 100644 --- a/src/events/command-handler/CorePreCommandRun.ts +++ b/src/events/command-handler/CorePreCommandRun.ts @@ -25,7 +25,7 @@ export class CoreEvent extends Event { return; } - const result = await command.preconditions.run(message, command); + const result = await command.preconditions.run(message, command, { command }); if (isErr(result)) { message.client.emit(Events.CommandDenied, result.error, payload); } else { diff --git a/src/lib/structures/Precondition.ts b/src/lib/structures/Precondition.ts index 40db8a48c..df899b313 100644 --- a/src/lib/structures/Precondition.ts +++ b/src/lib/structures/Precondition.ts @@ -24,4 +24,6 @@ export abstract class Precondition extends Piece { } } -export interface PreconditionContext extends Record {} +export interface PreconditionContext extends Record { + command: Command; +} diff --git a/src/lib/utils/preconditions/IPreconditionContainer.ts b/src/lib/utils/preconditions/IPreconditionContainer.ts index 5c55f0848..0b2f0ab96 100644 --- a/src/lib/utils/preconditions/IPreconditionContainer.ts +++ b/src/lib/utils/preconditions/IPreconditionContainer.ts @@ -1,8 +1,9 @@ import type { Awaited } from '@sapphire/pieces'; import type { Message } from 'discord.js'; import type { UserError } from '../../errors/UserError'; -import type { Command } from '../../structures/Command'; import type { Result } from '../../parsers/Result'; +import type { Command } from '../../structures/Command'; +import type { PreconditionContext } from '../../structures/Precondition'; /** * Defines the result's value for a PreconditionContainer. @@ -33,5 +34,5 @@ export interface IPreconditionContainer { * @param message The message that ran this precondition. * @param command The command the message invoked. */ - run(message: Message, command: Command): PreconditionContainerReturn; + run(message: Message, command: Command, context: PreconditionContext): PreconditionContainerReturn; } diff --git a/src/lib/utils/preconditions/PreconditionContainerArray.ts b/src/lib/utils/preconditions/PreconditionContainerArray.ts index 280656c6c..7aaeced32 100644 --- a/src/lib/utils/preconditions/PreconditionContainerArray.ts +++ b/src/lib/utils/preconditions/PreconditionContainerArray.ts @@ -1,5 +1,6 @@ import { Collection, Message } from 'discord.js'; import type { Command } from '../../structures/Command'; +import type { PreconditionContext } from '../../structures/Precondition'; import type { IPreconditionCondition } from './conditions/IPreconditionCondition'; import { PreconditionConditionAnd } from './conditions/PreconditionConditionAnd'; import { PreconditionConditionOr } from './conditions/PreconditionConditionOr'; @@ -151,10 +152,10 @@ export class PreconditionContainerArray implements IPreconditionContainer { * @param message The message that ran this precondition. * @param command The command the message invoked. */ - public run(message: Message, command: Command): PreconditionContainerReturn { + public run(message: Message, command: Command, context: PreconditionContext): PreconditionContainerReturn { return this.mode === PreconditionRunMode.Sequential - ? this.condition.sequential(message, command, this.entries) - : this.condition.parallel(message, command, this.entries); + ? this.condition.sequential(message, command, this.entries, context) + : this.condition.parallel(message, command, this.entries, context); } /** diff --git a/src/lib/utils/preconditions/PreconditionContainerSingle.ts b/src/lib/utils/preconditions/PreconditionContainerSingle.ts index 3fd153b43..b7944aa60 100644 --- a/src/lib/utils/preconditions/PreconditionContainerSingle.ts +++ b/src/lib/utils/preconditions/PreconditionContainerSingle.ts @@ -20,7 +20,7 @@ export interface PreconditionSingleResolvableDetails { * The context to be set at [[PreconditionContainerSingle.context]]. * @since 1.0.0 */ - context: PreconditionContext; + context: Record; } /** @@ -40,7 +40,7 @@ export class PreconditionContainerSingle implements IPreconditionContainer { * [[PreconditionSingleResolvableDetails.context]]. * @since 1.0.0 */ - public readonly context: PreconditionContext; + public readonly context: Record; /** * The name of the precondition to run. @@ -64,9 +64,9 @@ export class PreconditionContainerSingle implements IPreconditionContainer { * @param message The message that ran this precondition. * @param command The command the message invoked. */ - public run(message: Message, command: Command) { + public run(message: Message, command: Command, context: PreconditionContext) { const precondition = Store.injectedContext.stores.get('preconditions').get(this.name); - if (precondition) return precondition.run(message, command, this.context); + if (precondition) return precondition.run(message, command, { ...context, ...this.context }); throw new Error(`The precondition "${this.name}" is not available.`); } } diff --git a/src/lib/utils/preconditions/conditions/IPreconditionCondition.ts b/src/lib/utils/preconditions/conditions/IPreconditionCondition.ts index 90034ef90..65ce9838c 100644 --- a/src/lib/utils/preconditions/conditions/IPreconditionCondition.ts +++ b/src/lib/utils/preconditions/conditions/IPreconditionCondition.ts @@ -1,5 +1,6 @@ import type { Message } from 'discord.js'; import type { Command } from '../../../structures/Command'; +import type { PreconditionContext } from '../../../structures/Precondition'; import type { IPreconditionContainer, PreconditionContainerReturn } from '../IPreconditionContainer'; /** @@ -15,7 +16,12 @@ export interface IPreconditionCondition { * @param command The command the message invoked. * @param entries The containers to run. */ - sequential(message: Message, command: Command, entries: readonly IPreconditionContainer[]): PreconditionContainerReturn; + sequential( + message: Message, + command: Command, + entries: readonly IPreconditionContainer[], + context: PreconditionContext + ): PreconditionContainerReturn; /** * Runs all the containers using `Promise.all`, then checks the results once all tasks finished running. @@ -25,5 +31,10 @@ export interface IPreconditionCondition { * @param command The command the message invoked. * @param entries The containers to run. */ - parallel(message: Message, command: Command, entries: readonly IPreconditionContainer[]): PreconditionContainerReturn; + parallel( + message: Message, + command: Command, + entries: readonly IPreconditionContainer[], + context: PreconditionContext + ): PreconditionContainerReturn; } diff --git a/src/lib/utils/preconditions/conditions/PreconditionConditionAnd.ts b/src/lib/utils/preconditions/conditions/PreconditionConditionAnd.ts index af11e3f71..6cc60f895 100644 --- a/src/lib/utils/preconditions/conditions/PreconditionConditionAnd.ts +++ b/src/lib/utils/preconditions/conditions/PreconditionConditionAnd.ts @@ -6,16 +6,16 @@ import type { IPreconditionCondition } from './IPreconditionCondition'; * @since 1.0.0 */ export const PreconditionConditionAnd: IPreconditionCondition = { - async sequential(message, command, entries) { + async sequential(message, command, entries, context) { for (const child of entries) { - const result = await child.run(message, command); + const result = await child.run(message, command, context); if (isErr(result)) return result; } return ok(); }, - async parallel(message, command, entries) { - const results = await Promise.all(entries.map((entry) => entry.run(message, command))); + async parallel(message, command, entries, context) { + const results = await Promise.all(entries.map((entry) => entry.run(message, command, context))); // This is simplified compared to PreconditionContainerAny because we're looking for the first error. // However, the base implementation short-circuits with the first Ok. return results.find(isErr) ?? ok(); diff --git a/src/lib/utils/preconditions/conditions/PreconditionConditionOr.ts b/src/lib/utils/preconditions/conditions/PreconditionConditionOr.ts index 42f5886f6..f47024d6a 100644 --- a/src/lib/utils/preconditions/conditions/PreconditionConditionOr.ts +++ b/src/lib/utils/preconditions/conditions/PreconditionConditionOr.ts @@ -7,18 +7,18 @@ import type { IPreconditionCondition } from './IPreconditionCondition'; * @since 1.0.0 */ export const PreconditionConditionOr: IPreconditionCondition = { - async sequential(message, command, entries) { + async sequential(message, command, entries, context) { let error: PreconditionContainerResult | null = null; for (const child of entries) { - const result = await child.run(message, command); + const result = await child.run(message, command, context); if (isOk(result)) return result; error = result; } return error ?? ok(); }, - async parallel(message, command, entries) { - const results = await Promise.all(entries.map((entry) => entry.run(message, command))); + async parallel(message, command, entries, context) { + const results = await Promise.all(entries.map((entry) => entry.run(message, command, context))); let error: PreconditionContainerResult | null = null; for (const result of results) { diff --git a/src/lib/utils/preconditions/containers/PermissionsPrecondition.ts b/src/lib/utils/preconditions/containers/PermissionsPrecondition.ts index 66dd3c7cf..02308829e 100644 --- a/src/lib/utils/preconditions/containers/PermissionsPrecondition.ts +++ b/src/lib/utils/preconditions/containers/PermissionsPrecondition.ts @@ -1,5 +1,4 @@ import { PermissionResolvable, Permissions } from 'discord.js'; -import type { PreconditionContext } from '../../../structures/Precondition'; import type { PreconditionSingleResolvableDetails } from '../PreconditionContainerSingle'; /** @@ -25,7 +24,7 @@ import type { PreconditionSingleResolvableDetails } from '../PreconditionContain */ export class PermissionsPrecondition implements PreconditionSingleResolvableDetails { public name: string; - public context: PreconditionContext; + public context: Record; /** * Constructs a precondition container entry. diff --git a/src/preconditions/Cooldown.ts b/src/preconditions/Cooldown.ts index e47b08ff3..5706d843f 100644 --- a/src/preconditions/Cooldown.ts +++ b/src/preconditions/Cooldown.ts @@ -14,7 +14,11 @@ export class CorePrecondition extends Precondition { public buckets = new WeakMap>(); public run(message: Message, command: Command, context: CooldownContext) { - if (!context.delay || context.delay === 0) return this.ok(); + // If the command it is testing for is not this one, return ok: + if (context.command !== command) return this.ok(); + + // If there is no delay (undefined, null, 0), return ok: + if (!context.delay) return this.ok(); const bucket = this.getBucket(command, context); const remaining = bucket.take(this.getID(message, context));