Skip to content

Commit 2ed7fa5

Browse files
authoredAug 20, 2023
refactor(preconditions): add RunIn, deprecate everything else (#655)
* refactor(preconditions): add `RunIn`, deprecate everything else * fix: refactor `DMOnly` precondition * fix: correct string
1 parent 9103253 commit 2ed7fa5

15 files changed

+219
-221
lines changed
 

‎src/index.ts

+18-5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { CorePrecondition as GuildTextOnly } from './preconditions/GuildTextOnly
1818
import { CorePrecondition as GuildThreadOnly } from './preconditions/GuildThreadOnly';
1919
import { CorePrecondition as GuildVoiceOnly } from './preconditions/GuildVoiceOnly';
2020
import { CorePrecondition as NSFW } from './preconditions/NSFW';
21+
import { CorePrecondition as RunIn } from './preconditions/RunIn';
2122
import { CorePrecondition as UserPermissions } from './preconditions/UserPermissions';
2223

2324
const ApplicationCommandRegistries = {
@@ -32,12 +33,12 @@ const ApplicationCommandRegistries = {
3233
export {
3334
AliasPiece,
3435
AliasStore,
35-
container,
3636
LoaderError,
3737
MissingExportsError,
3838
Piece,
3939
Store,
4040
StoreRegistry,
41+
container,
4142
type AliasPieceOptions,
4243
type PieceContext,
4344
type PieceOptions,
@@ -46,6 +47,7 @@ export {
4647
} from '@sapphire/pieces';
4748
export * from '@sapphire/result';
4849
export type { Awaitable } from '@sapphire/utilities';
50+
export * from './lib/SapphireClient';
4951
export * from './lib/errors/ArgumentError';
5052
export * from './lib/errors/Identifiers';
5153
export * from './lib/errors/PreconditionError';
@@ -57,7 +59,6 @@ export * from './lib/plugins/symbols';
5759
export type { EmojiObject } from './lib/resolvers/emoji';
5860
export * as Resolvers from './lib/resolvers/index';
5961
export type { MessageResolverOptions } from './lib/resolvers/message';
60-
export * from './lib/SapphireClient';
6162
export * from './lib/structures/Argument';
6263
export * from './lib/structures/ArgumentStore';
6364
export * from './lib/structures/Command';
@@ -77,32 +78,44 @@ export {
7778
} from './lib/utils/application-commands/ApplicationCommandRegistry';
7879
export * from './lib/utils/logger/ILogger';
7980
export * from './lib/utils/logger/Logger';
81+
export * from './lib/utils/preconditions/IPreconditionContainer';
82+
export * from './lib/utils/preconditions/PreconditionContainerArray';
83+
export * from './lib/utils/preconditions/PreconditionContainerSingle';
8084
export * from './lib/utils/preconditions/conditions/IPreconditionCondition';
8185
export * from './lib/utils/preconditions/conditions/PreconditionConditionAnd';
8286
export * from './lib/utils/preconditions/conditions/PreconditionConditionOr';
8387
export * from './lib/utils/preconditions/containers/ClientPermissionsPrecondition';
8488
export * from './lib/utils/preconditions/containers/UserPermissionsPrecondition';
85-
export * from './lib/utils/preconditions/IPreconditionContainer';
86-
export * from './lib/utils/preconditions/PreconditionContainerArray';
87-
export * from './lib/utils/preconditions/PreconditionContainerSingle';
8889
export { ApplicationCommandRegistries };
8990

91+
/* eslint-disable deprecation/deprecation */
9092
export const CorePreconditions = {
9193
ClientPermissions,
9294
Cooldown,
95+
/** @deprecated Use {@link RunIn} instead. */
9396
DMOnly,
9497
Enabled,
98+
RunIn,
99+
/** @deprecated Use {@link RunIn} instead. */
95100
GuildNewsOnly,
101+
/** @deprecated Use {@link RunIn} instead. */
96102
GuildNewsThreadOnly,
103+
/** @deprecated Use {@link RunIn} instead. */
97104
GuildOnly,
105+
/** @deprecated Use {@link RunIn} instead. */
98106
GuildPrivateThreadOnly,
107+
/** @deprecated Use {@link RunIn} instead. */
99108
GuildPublicThreadOnly,
109+
/** @deprecated Use {@link RunIn} instead. */
100110
GuildTextOnly,
111+
/** @deprecated Use {@link RunIn} instead. */
101112
GuildVoiceOnly,
113+
/** @deprecated Use {@link RunIn} instead. */
102114
GuildThreadOnly,
103115
NSFW,
104116
UserPermissions
105117
};
118+
/* eslint-enable deprecation/deprecation */
106119

107120
export namespace CorePreconditions {
108121
export type UserPermissionsPreconditionContext = PermissionPreconditionContext;

‎src/lib/errors/Identifiers.ts

+10
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,30 @@ export enum Identifiers {
4545
CommandDisabled = 'commandDisabled',
4646

4747
PreconditionCooldown = 'preconditionCooldown',
48+
/** @deprecated Use {@link PreconditionRunIn} instead. */
4849
PreconditionDMOnly = 'preconditionDmOnly',
50+
/** @deprecated Use {@link PreconditionRunIn} instead. */
4951
PreconditionGuildNewsOnly = 'preconditionGuildNewsOnly',
52+
/** @deprecated Use {@link PreconditionRunIn} instead. */
5053
PreconditionGuildNewsThreadOnly = 'preconditionGuildNewsThreadOnly',
54+
/** @deprecated Use {@link PreconditionRunIn} instead. */
5155
PreconditionGuildOnly = 'preconditionGuildOnly',
56+
/** @deprecated Use {@link PreconditionRunIn} instead. */
5257
PreconditionGuildPrivateThreadOnly = 'preconditionGuildPrivateThreadOnly',
58+
/** @deprecated Use {@link PreconditionRunIn} instead. */
5359
PreconditionGuildPublicThreadOnly = 'preconditionGuildPublicThreadOnly',
60+
/** @deprecated Use {@link PreconditionRunIn} instead. */
5461
PreconditionGuildTextOnly = 'preconditionGuildTextOnly',
62+
/** @deprecated Use {@link PreconditionRunIn} instead. */
5563
PreconditionGuildVoiceOnly = 'preconditionGuildVoiceOnly',
5664
PreconditionNSFW = 'preconditionNsfw',
5765
PreconditionClientPermissions = 'preconditionClientPermissions',
5866
PreconditionClientPermissionsNoClient = 'preconditionClientPermissionsNoClient',
5967
PreconditionClientPermissionsNoPermissions = 'preconditionClientPermissionsNoPermissions',
68+
PreconditionRunIn = 'preconditionRunIn',
6069
PreconditionUserPermissions = 'preconditionUserPermissions',
6170
PreconditionUserPermissionsNoPermissions = 'preconditionUserPermissionsNoPermissions',
71+
/** @deprecated Use {@link PreconditionRunIn} instead. */
6272
PreconditionThreadOnly = 'preconditionThreadOnly',
6373

6474
PreconditionUnavailable = 'preconditionUnavailable',

‎src/lib/structures/Command.ts

+49-65
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ArgumentStream, Lexer, Parser, type IUnorderedStrategy } from '@sapphir
22
import { AliasPiece, type AliasPieceJSON } from '@sapphire/pieces';
33
import { isNullish, type Awaitable, type NonNullObject } from '@sapphire/utilities';
44
import {
5+
ChannelType,
56
ChatInputCommandInteraction,
67
ContextMenuCommandInteraction,
78
PermissionsBitField,
@@ -20,6 +21,9 @@ import { PreconditionContainerArray, type PreconditionEntryResolvable } from '..
2021
import { FlagUnorderedStrategy, type FlagStrategyOptions } from '../utils/strategies/FlagUnorderedStrategy';
2122
import type { CommandStore } from './CommandStore';
2223

24+
const ChannelTypes = Object.values(ChannelType).filter((type) => typeof type === 'number') as readonly ChannelType[];
25+
const GuildChannelTypes = ChannelTypes.filter((type) => type !== ChannelType.DM && type !== ChannelType.GroupDM) as readonly ChannelType[];
26+
2327
export class Command<PreParseReturn = Args, O extends Command.Options = Command.Options> extends AliasPiece<O> {
2428
/**
2529
* The {@link CommandStore} that contains this {@link Command}.
@@ -352,14 +356,15 @@ export class Command<PreParseReturn = Args, O extends Command.Options = Command.
352356
}
353357

354358
/**
355-
* Appends the `DMOnly`, `GuildOnly`, `NewsOnly`, and `TextOnly` preconditions based on the values passed in
356-
* {@link Command.Options.runIn}, optimizing in specific cases (`NewsOnly` + `TextOnly` = `GuildOnly`; `DMOnly` +
357-
* `GuildOnly` = `null`), defaulting to `null`, which doesn't add a precondition.
359+
* Appends the `RunIn` precondition based on the values passed, defaulting to `null`, which doesn't add a
360+
* precondition.
358361
* @param options The command options given from the constructor.
359362
*/
360363
protected parseConstructorPreConditionsRunIn(options: Command.Options) {
361-
const runIn = this.resolveConstructorPreConditionsRunType(options.runIn);
362-
if (runIn !== null) this.preconditions.append(runIn as any);
364+
const types = this.resolveConstructorPreConditionsRunType(options.runIn);
365+
if (types !== null) {
366+
this.preconditions.append({ name: CommandPreConditions.RunIn, context: { types } });
367+
}
363368
}
364369

365370
/**
@@ -411,87 +416,51 @@ export class Command<PreParseReturn = Args, O extends Command.Options = Command.
411416
}
412417
}
413418

414-
private resolveConstructorPreConditionsRunType(runIn: Command.Options['runIn']): PreconditionContainerArray | CommandPreConditions | null {
415-
if (isNullish(runIn)) return null;
416-
if (typeof runIn === 'string') {
417-
switch (runIn) {
419+
private resolveConstructorPreConditionsRunType(types: Command.Options['runIn']): readonly ChannelType[] | null {
420+
if (isNullish(types)) return null;
421+
if (typeof types === 'number') return [types];
422+
if (typeof types === 'string') {
423+
switch (types) {
418424
case 'DM':
419-
return CommandPreConditions.DirectMessageOnly;
425+
return [ChannelType.DM];
420426
case 'GUILD_TEXT':
421-
return CommandPreConditions.GuildTextOnly;
427+
return [ChannelType.GuildText];
422428
case 'GUILD_VOICE':
423-
return CommandPreConditions.GuildVoiceOnly;
429+
return [ChannelType.GuildVoice];
424430
case 'GUILD_NEWS':
425-
return CommandPreConditions.GuildNewsOnly;
431+
return [ChannelType.GuildAnnouncement];
426432
case 'GUILD_NEWS_THREAD':
427-
return CommandPreConditions.GuildNewsThreadOnly;
433+
return [ChannelType.AnnouncementThread];
428434
case 'GUILD_PUBLIC_THREAD':
429-
return CommandPreConditions.GuildPublicThreadOnly;
435+
return [ChannelType.PublicThread];
430436
case 'GUILD_PRIVATE_THREAD':
431-
return CommandPreConditions.GuildPrivateThreadOnly;
437+
return [ChannelType.PrivateThread];
432438
case 'GUILD_ANY':
433-
return CommandPreConditions.GuildOnly;
439+
return GuildChannelTypes;
434440
default:
435441
return null;
436442
}
437443
}
438444

439445
// If there's no channel it can run on, throw an error:
440-
if (runIn.length === 0) {
446+
if (types.length === 0) {
441447
throw new Error(`${this.constructor.name}[${this.name}]: "runIn" was specified as an empty array.`);
442448
}
443449

444-
if (runIn.length === 1) {
445-
return this.resolveConstructorPreConditionsRunType(runIn[0]);
450+
if (types.length === 1) {
451+
return this.resolveConstructorPreConditionsRunType(types[0]);
446452
}
447453

448-
const keys = new Set(runIn);
449-
450-
const dm = keys.has('DM');
451-
const guildText = keys.has('GUILD_TEXT');
452-
const guildVoice = keys.has('GUILD_VOICE');
453-
const guildNews = keys.has('GUILD_NEWS');
454-
const guild = guildText && guildNews && guildVoice;
455-
456-
// If runs everywhere, optimise to null:
457-
if (dm && guild) return null;
458-
459-
const guildPublicThread = keys.has('GUILD_PUBLIC_THREAD');
460-
const guildPrivateThread = keys.has('GUILD_PRIVATE_THREAD');
461-
const guildNewsThread = keys.has('GUILD_NEWS_THREAD');
462-
const guildThreads = guildPublicThread && guildPrivateThread && guildNewsThread;
463-
464-
// If runs in any thread, optimise to thread-only:
465-
if (guildThreads && keys.size === 3) {
466-
return CommandPreConditions.GuildThreadOnly;
454+
const resolved = new Set<ChannelType>();
455+
for (const typeResolvable of types) {
456+
for (const type of this.resolveConstructorPreConditionsRunType(typeResolvable) ?? []) resolved.add(type);
467457
}
468458

469-
const preconditions = new PreconditionContainerArray();
470-
if (dm) preconditions.append(CommandPreConditions.DirectMessageOnly);
471-
if (guild) {
472-
preconditions.append(CommandPreConditions.GuildOnly);
473-
} else {
474-
// GuildText includes PublicThread and PrivateThread
475-
if (guildText) {
476-
preconditions.append(CommandPreConditions.GuildTextOnly);
477-
} else {
478-
if (guildPublicThread) preconditions.append(CommandPreConditions.GuildPublicThreadOnly);
479-
if (guildPrivateThread) preconditions.append(CommandPreConditions.GuildPrivateThreadOnly);
480-
}
481-
482-
// GuildNews includes NewsThread
483-
if (guildNews) {
484-
preconditions.append(CommandPreConditions.GuildNewsOnly);
485-
} else if (guildNewsThread) {
486-
preconditions.append(CommandPreConditions.GuildNewsThreadOnly);
487-
}
488-
489-
if (guildVoice) {
490-
preconditions.append(CommandPreConditions.GuildVoiceOnly);
491-
}
492-
}
459+
// If all types were resolved, optimize to null:
460+
if (resolved.size === ChannelTypes.length) return null;
493461

494-
return preconditions;
462+
// Return the resolved types in ascending order:
463+
return [...resolved].sort((a, b) => a - b);
495464
}
496465
}
497466

@@ -577,14 +546,24 @@ export enum CommandOptionsRunTypeEnum {
577546
*/
578547
export enum CommandPreConditions {
579548
Cooldown = 'Cooldown',
549+
/** @deprecated Use {@link RunIn} instead. */
580550
DirectMessageOnly = 'DMOnly',
551+
RunIn = 'RunIn',
552+
/** @deprecated Use {@link RunIn} instead. */
581553
GuildNewsOnly = 'GuildNewsOnly',
554+
/** @deprecated Use {@link RunIn} instead. */
582555
GuildNewsThreadOnly = 'GuildNewsThreadOnly',
556+
/** @deprecated Use {@link RunIn} instead. */
583557
GuildOnly = 'GuildOnly',
558+
/** @deprecated Use {@link RunIn} instead. */
584559
GuildPrivateThreadOnly = 'GuildPrivateThreadOnly',
560+
/** @deprecated Use {@link RunIn} instead. */
585561
GuildPublicThreadOnly = 'GuildPublicThreadOnly',
562+
/** @deprecated Use {@link RunIn} instead. */
586563
GuildTextOnly = 'GuildTextOnly',
564+
/** @deprecated Use {@link RunIn} instead. */
587565
GuildVoiceOnly = 'GuildVoiceOnly',
566+
/** @deprecated Use {@link RunIn} instead. */
588567
GuildThreadOnly = 'GuildThreadOnly',
589568
NotSafeForWork = 'NSFW',
590569
ClientPermissions = 'ClientPermissions',
@@ -715,7 +694,12 @@ export interface CommandOptions extends AliasPiece.Options, FlagStrategyOptions
715694
* @since 2.0.0
716695
* @default null
717696
*/
718-
runIn?: Command.RunInTypes | CommandOptionsRunTypeEnum | readonly (Command.RunInTypes | CommandOptionsRunTypeEnum)[] | null;
697+
runIn?:
698+
| ChannelType
699+
| Command.RunInTypes
700+
| CommandOptionsRunTypeEnum
701+
| readonly (ChannelType | Command.RunInTypes | CommandOptionsRunTypeEnum)[]
702+
| null;
719703

720704
/**
721705
* If {@link SapphireClient.typing} is true, this option will override it.

‎src/lib/structures/Precondition.ts

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Piece } from '@sapphire/pieces';
22
import { Result } from '@sapphire/result';
33
import type { Awaitable } from '@sapphire/utilities';
44
import type {
5+
ChannelType,
56
ChatInputCommandInteraction,
67
CommandInteraction,
78
ContextMenuCommandInteraction,
@@ -139,6 +140,9 @@ export interface Preconditions {
139140
GuildVoiceOnly: never;
140141
GuildThreadOnly: never;
141142
NSFW: never;
143+
RunIn: {
144+
types: readonly ChannelType[];
145+
};
142146
ClientPermissions: {
143147
permissions: PermissionsBitField;
144148
};

‎src/preconditions/DMOnly.ts

+11-9
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,22 @@ import { AllFlowsPrecondition } from '../lib/structures/Precondition';
44

55
export class CorePrecondition extends AllFlowsPrecondition {
66
public messageRun(message: Message): AllFlowsPrecondition.Result {
7-
return message.guild === null
8-
? this.ok()
9-
: this.error({ identifier: Identifiers.PreconditionDMOnly, message: 'You cannot run this message command outside DMs.' });
7+
return message.guild === null ? this.ok() : this.makeSharedError();
108
}
119

1210
public chatInputRun(interaction: ChatInputCommandInteraction): AllFlowsPrecondition.Result {
13-
return interaction.guildId === null
14-
? this.ok()
15-
: this.error({ identifier: Identifiers.PreconditionDMOnly, message: 'You cannot run this chat input command outside DMs.' });
11+
return interaction.guildId === null ? this.ok() : this.makeSharedError();
1612
}
1713

1814
public contextMenuRun(interaction: ContextMenuCommandInteraction): AllFlowsPrecondition.Result {
19-
return interaction.guildId === null
20-
? this.ok()
21-
: this.error({ identifier: Identifiers.PreconditionDMOnly, message: 'You cannot run this context menu command outside DMs.' });
15+
return interaction.guildId === null ? this.ok() : this.makeSharedError();
16+
}
17+
18+
private makeSharedError(): AllFlowsPrecondition.Result {
19+
return this.error({
20+
// eslint-disable-next-line deprecation/deprecation
21+
identifier: Identifiers.PreconditionDMOnly,
22+
message: 'You cannot run this command outside DMs.'
23+
});
2224
}
2325
}

‎src/preconditions/GuildNewsOnly.ts

+11-18
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,26 @@ export class CorePrecondition extends AllFlowsPrecondition {
66
private readonly allowedTypes: TextBasedChannelTypes[] = [ChannelType.GuildAnnouncement, ChannelType.AnnouncementThread];
77

88
public messageRun(message: Message): AllFlowsPrecondition.Result {
9-
return this.allowedTypes.includes(message.channel.type)
10-
? this.ok()
11-
: this.error({
12-
identifier: Identifiers.PreconditionGuildNewsOnly,
13-
message: 'You can only run this message command in server announcement channels.'
14-
});
9+
return this.allowedTypes.includes(message.channel.type) ? this.ok() : this.makeSharedError();
1510
}
1611

1712
public async chatInputRun(interaction: ChatInputCommandInteraction): AllFlowsPrecondition.AsyncResult {
1813
const channel = await this.fetchChannelFromInteraction(interaction);
1914

20-
return this.allowedTypes.includes(channel.type)
21-
? this.ok()
22-
: this.error({
23-
identifier: Identifiers.PreconditionGuildNewsOnly,
24-
message: 'You can only run this chat input command in server announcement channels.'
25-
});
15+
return this.allowedTypes.includes(channel.type) ? this.ok() : this.makeSharedError();
2616
}
2717

2818
public async contextMenuRun(interaction: ContextMenuCommandInteraction): AllFlowsPrecondition.AsyncResult {
2919
const channel = await this.fetchChannelFromInteraction(interaction);
3020

31-
return this.allowedTypes.includes(channel.type)
32-
? this.ok()
33-
: this.error({
34-
identifier: Identifiers.PreconditionGuildNewsOnly,
35-
message: 'You can only run this context menu command in server announcement channels.'
36-
});
21+
return this.allowedTypes.includes(channel.type) ? this.ok() : this.makeSharedError();
22+
}
23+
24+
private makeSharedError(): AllFlowsPrecondition.Result {
25+
return this.error({
26+
// eslint-disable-next-line deprecation/deprecation
27+
identifier: Identifiers.PreconditionGuildNewsOnly,
28+
message: 'You can only run this command in server announcement channels.'
29+
});
3730
}
3831
}

‎src/preconditions/GuildNewsThreadOnly.ts

+10-19
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,24 @@ import { AllFlowsPrecondition } from '../lib/structures/Precondition';
44

55
export class CorePrecondition extends AllFlowsPrecondition {
66
public messageRun(message: Message): AllFlowsPrecondition.Result {
7-
return message.thread?.type === ChannelType.AnnouncementThread
8-
? this.ok()
9-
: this.error({
10-
identifier: Identifiers.PreconditionGuildNewsThreadOnly,
11-
message: 'You can only run this message command in server announcement thread channels.'
12-
});
7+
return message.thread?.type === ChannelType.AnnouncementThread ? this.ok() : this.makeSharedError();
138
}
149

1510
public async chatInputRun(interaction: ChatInputCommandInteraction): AllFlowsPrecondition.AsyncResult {
1611
const channel = await this.fetchChannelFromInteraction(interaction);
17-
18-
return channel.type === ChannelType.AnnouncementThread
19-
? this.ok()
20-
: this.error({
21-
identifier: Identifiers.PreconditionGuildNewsThreadOnly,
22-
message: 'You can only run this chat input command in server announcement thread channels.'
23-
});
12+
return channel.type === ChannelType.AnnouncementThread ? this.ok() : this.makeSharedError();
2413
}
2514

2615
public async contextMenuRun(interaction: ContextMenuCommandInteraction): AllFlowsPrecondition.AsyncResult {
2716
const channel = await this.fetchChannelFromInteraction(interaction);
17+
return channel.type === ChannelType.AnnouncementThread ? this.ok() : this.makeSharedError();
18+
}
2819

29-
return channel.type === ChannelType.AnnouncementThread
30-
? this.ok()
31-
: this.error({
32-
identifier: Identifiers.PreconditionGuildNewsThreadOnly,
33-
message: 'You can only run this context menu command in server announcement thread channels.'
34-
});
20+
private makeSharedError(): AllFlowsPrecondition.Result {
21+
return this.error({
22+
// eslint-disable-next-line deprecation/deprecation
23+
identifier: Identifiers.PreconditionGuildNewsThreadOnly,
24+
message: 'You can only run this command in server announcement thread channels.'
25+
});
3526
}
3627
}

‎src/preconditions/GuildOnly.ts

+11-9
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,22 @@ import { AllFlowsPrecondition } from '../lib/structures/Precondition';
44

55
export class CorePrecondition extends AllFlowsPrecondition {
66
public messageRun(message: Message): AllFlowsPrecondition.Result {
7-
return message.guildId === null
8-
? this.error({ identifier: Identifiers.PreconditionGuildOnly, message: 'You cannot run this message command in DMs.' })
9-
: this.ok();
7+
return message.guildId === null ? this.makeSharedError() : this.ok();
108
}
119

1210
public chatInputRun(interaction: ChatInputCommandInteraction): AllFlowsPrecondition.Result {
13-
return interaction.guildId === null
14-
? this.error({ identifier: Identifiers.PreconditionGuildOnly, message: 'You cannot run this chat input command in DMs.' })
15-
: this.ok();
11+
return interaction.guildId === null ? this.makeSharedError() : this.ok();
1612
}
1713

1814
public contextMenuRun(interaction: ContextMenuCommandInteraction): AllFlowsPrecondition.Result {
19-
return interaction.guildId === null
20-
? this.error({ identifier: Identifiers.PreconditionGuildOnly, message: 'You cannot run this context menu command in DMs.' })
21-
: this.ok();
15+
return interaction.guildId === null ? this.makeSharedError() : this.ok();
16+
}
17+
18+
private makeSharedError(): AllFlowsPrecondition.Result {
19+
return this.error({
20+
// eslint-disable-next-line deprecation/deprecation
21+
identifier: Identifiers.PreconditionGuildOnly,
22+
message: 'You cannot run this command in DMs.'
23+
});
2224
}
2325
}

‎src/preconditions/GuildPrivateThreadOnly.ts

+10-19
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,24 @@ import { AllFlowsPrecondition } from '../lib/structures/Precondition';
44

55
export class CorePrecondition extends AllFlowsPrecondition {
66
public messageRun(message: Message): AllFlowsPrecondition.Result {
7-
return message.thread?.type === ChannelType.PrivateThread
8-
? this.ok()
9-
: this.error({
10-
identifier: Identifiers.PreconditionGuildPrivateThreadOnly,
11-
message: 'You can only run this message command in private server thread channels.'
12-
});
7+
return message.thread?.type === ChannelType.PrivateThread ? this.ok() : this.makeSharedError();
138
}
149

1510
public async chatInputRun(interaction: ChatInputCommandInteraction): AllFlowsPrecondition.AsyncResult {
1611
const channel = await this.fetchChannelFromInteraction(interaction);
17-
18-
return channel.type === ChannelType.PrivateThread
19-
? this.ok()
20-
: this.error({
21-
identifier: Identifiers.PreconditionGuildPrivateThreadOnly,
22-
message: 'You can only run this chat input command in private server thread channels.'
23-
});
12+
return channel.type === ChannelType.PrivateThread ? this.ok() : this.makeSharedError();
2413
}
2514

2615
public async contextMenuRun(interaction: ContextMenuCommandInteraction): AllFlowsPrecondition.AsyncResult {
2716
const channel = await this.fetchChannelFromInteraction(interaction);
17+
return channel.type === ChannelType.PrivateThread ? this.ok() : this.makeSharedError();
18+
}
2819

29-
return channel.type === ChannelType.PrivateThread
30-
? this.ok()
31-
: this.error({
32-
identifier: Identifiers.PreconditionGuildPrivateThreadOnly,
33-
message: 'You can only run this context menu command in private server thread channels.'
34-
});
20+
private makeSharedError(): AllFlowsPrecondition.Result {
21+
return this.error({
22+
// eslint-disable-next-line deprecation/deprecation
23+
identifier: Identifiers.PreconditionGuildPrivateThreadOnly,
24+
message: 'You can only run this command in private server thread channels.'
25+
});
3526
}
3627
}

‎src/preconditions/GuildPublicThreadOnly.ts

+10-19
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,24 @@ import { AllFlowsPrecondition } from '../lib/structures/Precondition';
44

55
export class CorePrecondition extends AllFlowsPrecondition {
66
public messageRun(message: Message): AllFlowsPrecondition.Result {
7-
return message.thread?.type === ChannelType.PublicThread
8-
? this.ok()
9-
: this.error({
10-
identifier: Identifiers.PreconditionGuildPublicThreadOnly,
11-
message: 'You can only run this message command in public server thread channels.'
12-
});
7+
return message.thread?.type === ChannelType.PublicThread ? this.ok() : this.makeSharedError();
138
}
149

1510
public async chatInputRun(interaction: ChatInputCommandInteraction): AllFlowsPrecondition.AsyncResult {
1611
const channel = await this.fetchChannelFromInteraction(interaction);
17-
18-
return channel.type === ChannelType.PublicThread
19-
? this.ok()
20-
: this.error({
21-
identifier: Identifiers.PreconditionGuildPublicThreadOnly,
22-
message: 'You can only run this chat input command in public server thread channels.'
23-
});
12+
return channel.type === ChannelType.PublicThread ? this.ok() : this.makeSharedError();
2413
}
2514

2615
public async contextMenuRun(interaction: ContextMenuCommandInteraction): AllFlowsPrecondition.AsyncResult {
2716
const channel = await this.fetchChannelFromInteraction(interaction);
17+
return channel.type === ChannelType.PublicThread ? this.ok() : this.makeSharedError();
18+
}
2819

29-
return channel.type === ChannelType.PublicThread
30-
? this.ok()
31-
: this.error({
32-
identifier: Identifiers.PreconditionGuildPublicThreadOnly,
33-
message: 'You can only run this context menu command in public server thread channels.'
34-
});
20+
private makeSharedError(): AllFlowsPrecondition.Result {
21+
return this.error({
22+
// eslint-disable-next-line deprecation/deprecation
23+
identifier: Identifiers.PreconditionGuildPublicThreadOnly,
24+
message: 'You can only run this command in public server thread channels.'
25+
});
3526
}
3627
}

‎src/preconditions/GuildTextOnly.ts

+10-19
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,24 @@ export class CorePrecondition extends AllFlowsPrecondition {
66
private readonly allowedTypes: TextBasedChannelTypes[] = [ChannelType.GuildText, ChannelType.PublicThread, ChannelType.PrivateThread];
77

88
public messageRun(message: Message): AllFlowsPrecondition.Result {
9-
return this.allowedTypes.includes(message.channel.type)
10-
? this.ok()
11-
: this.error({
12-
identifier: Identifiers.PreconditionGuildTextOnly,
13-
message: 'You can only run this message command in server text channels.'
14-
});
9+
return this.allowedTypes.includes(message.channel.type) ? this.ok() : this.makeSharedError();
1510
}
1611

1712
public async chatInputRun(interaction: ChatInputCommandInteraction): AllFlowsPrecondition.AsyncResult {
1813
const channel = await this.fetchChannelFromInteraction(interaction);
19-
20-
return this.allowedTypes.includes(channel.type)
21-
? this.ok()
22-
: this.error({
23-
identifier: Identifiers.PreconditionGuildTextOnly,
24-
message: 'You can only run this chat input command in server text channels.'
25-
});
14+
return this.allowedTypes.includes(channel.type) ? this.ok() : this.makeSharedError();
2615
}
2716

2817
public async contextMenuRun(interaction: ContextMenuCommandInteraction): AllFlowsPrecondition.AsyncResult {
2918
const channel = await this.fetchChannelFromInteraction(interaction);
19+
return this.allowedTypes.includes(channel.type) ? this.ok() : this.makeSharedError();
20+
}
3021

31-
return this.allowedTypes.includes(channel.type)
32-
? this.ok()
33-
: this.error({
34-
identifier: Identifiers.PreconditionGuildTextOnly,
35-
message: 'You can only run this context menu command in server text channels.'
36-
});
22+
private makeSharedError(): AllFlowsPrecondition.Result {
23+
return this.error({
24+
// eslint-disable-next-line deprecation/deprecation
25+
identifier: Identifiers.PreconditionGuildTextOnly,
26+
message: 'You can only run this command in server text channels.'
27+
});
3728
}
3829
}

‎src/preconditions/GuildThreadOnly.ts

+10-19
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,24 @@ import { AllFlowsPrecondition } from '../lib/structures/Precondition';
44

55
export class CorePrecondition extends AllFlowsPrecondition {
66
public messageRun(message: Message): AllFlowsPrecondition.Result {
7-
return message.thread
8-
? this.ok()
9-
: this.error({
10-
identifier: Identifiers.PreconditionThreadOnly,
11-
message: 'You can only run this message command in server thread channels.'
12-
});
7+
return message.thread ? this.ok() : this.makeSharedError();
138
}
149

1510
public async chatInputRun(interaction: ChatInputCommandInteraction): AllFlowsPrecondition.AsyncResult {
1611
const channel = await this.fetchChannelFromInteraction(interaction);
17-
18-
return channel.isThread()
19-
? this.ok()
20-
: this.error({
21-
identifier: Identifiers.PreconditionThreadOnly,
22-
message: 'You can only run this chat input command in server thread channels.'
23-
});
12+
return channel.isThread() ? this.ok() : this.makeSharedError();
2413
}
2514

2615
public async contextMenuRun(interaction: ContextMenuCommandInteraction): AllFlowsPrecondition.AsyncResult {
2716
const channel = await this.fetchChannelFromInteraction(interaction);
17+
return channel.isThread() ? this.ok() : this.makeSharedError();
18+
}
2819

29-
return channel.isThread()
30-
? this.ok()
31-
: this.error({
32-
identifier: Identifiers.PreconditionThreadOnly,
33-
message: 'You can only run this context menu command in server thread channels.'
34-
});
20+
private makeSharedError(): AllFlowsPrecondition.Result {
21+
return this.error({
22+
// eslint-disable-next-line deprecation/deprecation
23+
identifier: Identifiers.PreconditionThreadOnly,
24+
message: 'You can only run this command in server thread channels.'
25+
});
3526
}
3627
}

‎src/preconditions/GuildVoiceOnly.ts

+10-19
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,24 @@ import { AllFlowsPrecondition } from '../lib/structures/Precondition';
55

66
export class CorePrecondition extends AllFlowsPrecondition {
77
public messageRun(message: Message): AllFlowsPrecondition.Result {
8-
return isVoiceChannel(message.channel)
9-
? this.ok()
10-
: this.error({
11-
identifier: Identifiers.PreconditionGuildVoiceOnly,
12-
message: 'You can only run this message command in server voice channels.'
13-
});
8+
return isVoiceChannel(message.channel) ? this.ok() : this.makeSharedError();
149
}
1510

1611
public async chatInputRun(interaction: ChatInputCommandInteraction): AllFlowsPrecondition.AsyncResult {
1712
const channel = await this.fetchChannelFromInteraction(interaction);
18-
19-
return isVoiceChannel(channel)
20-
? this.ok()
21-
: this.error({
22-
identifier: Identifiers.PreconditionGuildVoiceOnly,
23-
message: 'You can only run this chat input command in server voice channels.'
24-
});
13+
return isVoiceChannel(channel) ? this.ok() : this.makeSharedError();
2514
}
2615

2716
public async contextMenuRun(interaction: ContextMenuCommandInteraction): AllFlowsPrecondition.AsyncResult {
2817
const channel = await this.fetchChannelFromInteraction(interaction);
18+
return isVoiceChannel(channel) ? this.ok() : this.makeSharedError();
19+
}
2920

30-
return isVoiceChannel(channel)
31-
? this.ok()
32-
: this.error({
33-
identifier: Identifiers.PreconditionGuildVoiceOnly,
34-
message: 'You can only run this context menu command in server voice channels.'
35-
});
21+
private makeSharedError(): AllFlowsPrecondition.Result {
22+
return this.error({
23+
// eslint-disable-next-line deprecation/deprecation
24+
identifier: Identifiers.PreconditionGuildVoiceOnly,
25+
message: 'You can only run this command in server voice channels.'
26+
});
3627
}
3728
}

‎src/preconditions/NSFW.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,6 @@ export class CorePrecondition extends AllFlowsPrecondition {
2828
// will result on it returning `false`.
2929
return Reflect.get(channel, 'nsfw') === true
3030
? this.ok()
31-
: this.error({ identifier: Identifiers.PreconditionNSFW, message: 'You cannot run this context menu command outside NSFW channels.' });
31+
: this.error({ identifier: Identifiers.PreconditionNSFW, message: 'You cannot run this command outside NSFW channels.' });
3232
}
3333
}

‎src/preconditions/RunIn.ts

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import type { ChannelType, ChatInputCommandInteraction, ContextMenuCommandInteraction, Message } from 'discord.js';
2+
import { Identifiers } from '../lib/errors/Identifiers';
3+
import type { ChatInputCommand, ContextMenuCommand, MessageCommand } from '../lib/structures/Command';
4+
import { AllFlowsPrecondition } from '../lib/structures/Precondition';
5+
6+
export interface RunInPreconditionContext extends AllFlowsPrecondition.Context {
7+
types?: readonly ChannelType[];
8+
}
9+
10+
export class CorePrecondition extends AllFlowsPrecondition {
11+
public override messageRun(message: Message<boolean>, _: MessageCommand, context: RunInPreconditionContext): AllFlowsPrecondition.Result {
12+
return context.types && context.types.includes(message.channel.type) //
13+
? this.ok()
14+
: this.makeSharedError(context);
15+
}
16+
17+
public override async chatInputRun(
18+
interaction: ChatInputCommandInteraction,
19+
_: ChatInputCommand,
20+
context: RunInPreconditionContext
21+
): AllFlowsPrecondition.AsyncResult {
22+
return context.types && context.types.includes((await this.fetchChannelFromInteraction(interaction)).type)
23+
? this.ok()
24+
: this.makeSharedError(context);
25+
}
26+
27+
public override async contextMenuRun(
28+
interaction: ContextMenuCommandInteraction,
29+
_: ContextMenuCommand,
30+
context: RunInPreconditionContext
31+
): AllFlowsPrecondition.AsyncResult {
32+
return context.types && context.types.includes((await this.fetchChannelFromInteraction(interaction)).type)
33+
? this.ok()
34+
: this.makeSharedError(context);
35+
}
36+
37+
private makeSharedError(context: RunInPreconditionContext): AllFlowsPrecondition.Result {
38+
return this.error({
39+
identifier: Identifiers.PreconditionRunIn,
40+
message: 'You cannot run this message command in this type of channel.',
41+
context: { types: context.types }
42+
});
43+
}
44+
}

0 commit comments

Comments
 (0)
Please sign in to comment.