Skip to content

Commit 07c1210

Browse files
authored
fix: slashcommand builder type split (discordjs#10253)
1 parent 30d79e8 commit 07c1210

File tree

6 files changed

+135
-112
lines changed

6 files changed

+135
-112
lines changed

packages/builders/__tests__/interactions/SlashCommands/SlashCommands.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,10 @@ describe('Slash Commands', () => {
357357
getBuilder().addStringOption(getStringOption().setChoices({ name: 'owo', value: 'uwu' })),
358358
).not.toThrowError();
359359
});
360+
361+
test('GIVEN valid builder with NSFW, THEN does not throw error', () => {
362+
expect(() => getBuilder().setName('foo').setDescription('foo').setNSFW(true)).not.toThrowError();
363+
});
360364
});
361365

362366
describe('Builder with subcommand (group) options', () => {
@@ -519,6 +523,14 @@ describe('Slash Commands', () => {
519523

520524
expect(() => getBuilder().setDefaultMemberPermissions(1.1)).toThrowError();
521525
});
526+
527+
test('GIVEN valid permission with options THEN does not throw error', () => {
528+
expect(() =>
529+
getBuilder().addBooleanOption(getBooleanOption()).setDefaultMemberPermissions('1'),
530+
).not.toThrowError();
531+
532+
expect(() => getBuilder().addChannelOption(getChannelOption()).setDMPermission(false)).not.toThrowError();
533+
});
522534
});
523535
});
524536
});

packages/builders/src/components/textInput/TextInput.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ export class TextInputBuilder
140140
}
141141

142142
/**
143-
* {@inheritDoc Equatable.equals}
143+
* Whether this is equal to another structure.
144144
*/
145145
public equals(other: APITextInputComponent | JSONEncodable<APITextInputComponent>): boolean {
146146
if (isJSONEncodable(other)) {

packages/builders/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export * from './interactions/slashCommands/mixins/ApplicationCommandOptionWithC
5454
export * from './interactions/slashCommands/mixins/NameAndDescription.js';
5555
export * from './interactions/slashCommands/mixins/SharedSlashCommandOptions.js';
5656
export * from './interactions/slashCommands/mixins/SharedSubcommands.js';
57+
export * from './interactions/slashCommands/mixins/SharedSlashCommand.js';
5758

5859
export * as ContextMenuCommandAssertions from './interactions/contextMenuCommands/Assertions.js';
5960
export * from './interactions/contextMenuCommands/ContextMenuCommandBuilder.js';

packages/builders/src/interactions/slashCommands/SlashCommandBuilder.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import type { APIApplicationCommandOption, LocalizationMap, Permissions } from 'discord-api-types/v10';
22
import { mix } from 'ts-mixer';
33
import { SharedNameAndDescription } from './mixins/NameAndDescription.js';
4+
import { SharedSlashCommand } from './mixins/SharedSlashCommand.js';
45
import { SharedSlashCommandOptions } from './mixins/SharedSlashCommandOptions.js';
56
import { SharedSlashCommandSubcommands } from './mixins/SharedSubcommands.js';
67

78
/**
89
* A builder that creates API-compatible JSON data for slash commands.
910
*/
10-
@mix(SharedSlashCommandOptions, SharedNameAndDescription, SharedSlashCommandSubcommands)
11+
@mix(SharedSlashCommandOptions, SharedNameAndDescription, SharedSlashCommandSubcommands, SharedSlashCommand)
1112
export class SlashCommandBuilder {
1213
/**
1314
* The name of this command.
@@ -37,7 +38,7 @@ export class SlashCommandBuilder {
3738
/**
3839
* Whether this command is enabled by default when the application is added to a guild.
3940
*
40-
* @deprecated Use {@link SharedSlashCommandSubcommands.setDefaultMemberPermissions} or {@link SharedSlashCommandSubcommands.setDMPermission} instead.
41+
* @deprecated Use {@link SharedSlashCommand.setDefaultMemberPermissions} or {@link SharedSlashCommand.setDMPermission} instead.
4142
*/
4243
public readonly default_permission: boolean | undefined = undefined;
4344

@@ -63,22 +64,24 @@ export class SlashCommandBuilder {
6364
export interface SlashCommandBuilder
6465
extends SharedNameAndDescription,
6566
SharedSlashCommandOptions<SlashCommandOptionsOnlyBuilder>,
66-
SharedSlashCommandSubcommands<SlashCommandSubcommandsOnlyBuilder> {}
67+
SharedSlashCommandSubcommands<SlashCommandSubcommandsOnlyBuilder>,
68+
SharedSlashCommand {}
6769

6870
/**
6971
* An interface specifically for slash command subcommands.
7072
*/
7173
export interface SlashCommandSubcommandsOnlyBuilder
7274
extends SharedNameAndDescription,
73-
SharedSlashCommandSubcommands<SlashCommandSubcommandsOnlyBuilder> {}
75+
SharedSlashCommandSubcommands<SlashCommandSubcommandsOnlyBuilder>,
76+
SharedSlashCommand {}
7477

7578
/**
7679
* An interface specifically for slash command options.
7780
*/
7881
export interface SlashCommandOptionsOnlyBuilder
7982
extends SharedNameAndDescription,
8083
SharedSlashCommandOptions<SlashCommandOptionsOnlyBuilder>,
81-
ToAPIApplicationCommandOptions {}
84+
SharedSlashCommand {}
8285

8386
/**
8487
* An interface that ensures the `toJSON()` call will return something
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import type {
2+
LocalizationMap,
3+
Permissions,
4+
RESTPostAPIChatInputApplicationCommandsJSONBody,
5+
} from 'discord-api-types/v10';
6+
import {
7+
validateDMPermission,
8+
validateDefaultMemberPermissions,
9+
validateDefaultPermission,
10+
validateLocalizationMap,
11+
validateNSFW,
12+
validateRequiredParameters,
13+
} from '../Assertions.js';
14+
import type { ToAPIApplicationCommandOptions } from '../SlashCommandBuilder.js';
15+
16+
/**
17+
* This mixin holds symbols that can be shared in slashcommands independent of options or subcommands.
18+
*/
19+
export class SharedSlashCommand {
20+
public readonly name: string = undefined!;
21+
22+
public readonly name_localizations?: LocalizationMap;
23+
24+
public readonly description: string = undefined!;
25+
26+
public readonly description_localizations?: LocalizationMap;
27+
28+
public readonly options: ToAPIApplicationCommandOptions[] = [];
29+
30+
/**
31+
* Sets whether the command is enabled by default when the application is added to a guild.
32+
*
33+
* @remarks
34+
* If set to `false`, you will have to later `PUT` the permissions for this command.
35+
* @param value - Whether or not to enable this command by default
36+
* @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions}
37+
* @deprecated Use {@link SharedSlashCommand.setDefaultMemberPermissions} or {@link SharedSlashCommand.setDMPermission} instead.
38+
*/
39+
public setDefaultPermission(value: boolean) {
40+
// Assert the value matches the conditions
41+
validateDefaultPermission(value);
42+
43+
Reflect.set(this, 'default_permission', value);
44+
45+
return this;
46+
}
47+
48+
/**
49+
* Sets the default permissions a member should have in order to run the command.
50+
*
51+
* @remarks
52+
* You can set this to `'0'` to disable the command by default.
53+
* @param permissions - The permissions bit field to set
54+
* @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions}
55+
*/
56+
public setDefaultMemberPermissions(permissions: Permissions | bigint | number | null | undefined) {
57+
// Assert the value and parse it
58+
const permissionValue = validateDefaultMemberPermissions(permissions);
59+
60+
Reflect.set(this, 'default_member_permissions', permissionValue);
61+
62+
return this;
63+
}
64+
65+
/**
66+
* Sets if the command is available in direct messages with the application.
67+
*
68+
* @remarks
69+
* By default, commands are visible. This method is only for global commands.
70+
* @param enabled - Whether the command should be enabled in direct messages
71+
* @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions}
72+
*/
73+
public setDMPermission(enabled: boolean | null | undefined) {
74+
// Assert the value matches the conditions
75+
validateDMPermission(enabled);
76+
77+
Reflect.set(this, 'dm_permission', enabled);
78+
79+
return this;
80+
}
81+
82+
/**
83+
* Sets whether this command is NSFW.
84+
*
85+
* @param nsfw - Whether this command is NSFW
86+
*/
87+
public setNSFW(nsfw = true) {
88+
// Assert the value matches the conditions
89+
validateNSFW(nsfw);
90+
Reflect.set(this, 'nsfw', nsfw);
91+
return this;
92+
}
93+
94+
/**
95+
* Serializes this builder to API-compatible JSON data.
96+
*
97+
* @remarks
98+
* This method runs validations on the data before serializing it.
99+
* As such, it may throw an error if the data is invalid.
100+
*/
101+
public toJSON(): RESTPostAPIChatInputApplicationCommandsJSONBody {
102+
validateRequiredParameters(this.name, this.description, this.options);
103+
104+
validateLocalizationMap(this.name_localizations);
105+
validateLocalizationMap(this.description_localizations);
106+
107+
return {
108+
...this,
109+
options: this.options.map((option) => option.toJSON()),
110+
};
111+
}
112+
}
Lines changed: 1 addition & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,4 @@
1-
import type {
2-
LocalizationMap,
3-
Permissions,
4-
RESTPostAPIChatInputApplicationCommandsJSONBody,
5-
} from 'discord-api-types/v10';
6-
import {
7-
assertReturnOfBuilder,
8-
validateDMPermission,
9-
validateDefaultMemberPermissions,
10-
validateDefaultPermission,
11-
validateLocalizationMap,
12-
validateMaxOptionsLength,
13-
validateNSFW,
14-
validateRequiredParameters,
15-
} from '../Assertions.js';
1+
import { assertReturnOfBuilder, validateMaxOptionsLength } from '../Assertions.js';
162
import type { ToAPIApplicationCommandOptions } from '../SlashCommandBuilder.js';
173
import { SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder } from '../SlashCommandSubcommands.js';
184

@@ -24,80 +10,8 @@ import { SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder } fro
2410
export class SharedSlashCommandSubcommands<
2511
TypeAfterAddingSubcommands extends SharedSlashCommandSubcommands<TypeAfterAddingSubcommands>,
2612
> {
27-
public readonly name: string = undefined!;
28-
29-
public readonly name_localizations?: LocalizationMap;
30-
31-
public readonly description: string = undefined!;
32-
33-
public readonly description_localizations?: LocalizationMap;
34-
3513
public readonly options: ToAPIApplicationCommandOptions[] = [];
3614

37-
/**
38-
* Sets whether the command is enabled by default when the application is added to a guild.
39-
*
40-
* @remarks
41-
* If set to `false`, you will have to later `PUT` the permissions for this command.
42-
* @param value - Whether or not to enable this command by default
43-
* @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions}
44-
* @deprecated Use {@link SharedSlashCommandSubcommands.setDefaultMemberPermissions} or {@link SharedSlashCommandSubcommands.setDMPermission} instead.
45-
*/
46-
public setDefaultPermission(value: boolean) {
47-
// Assert the value matches the conditions
48-
validateDefaultPermission(value);
49-
50-
Reflect.set(this, 'default_permission', value);
51-
52-
return this;
53-
}
54-
55-
/**
56-
* Sets the default permissions a member should have in order to run the command.
57-
*
58-
* @remarks
59-
* You can set this to `'0'` to disable the command by default.
60-
* @param permissions - The permissions bit field to set
61-
* @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions}
62-
*/
63-
public setDefaultMemberPermissions(permissions: Permissions | bigint | number | null | undefined) {
64-
// Assert the value and parse it
65-
const permissionValue = validateDefaultMemberPermissions(permissions);
66-
67-
Reflect.set(this, 'default_member_permissions', permissionValue);
68-
69-
return this;
70-
}
71-
72-
/**
73-
* Sets if the command is available in direct messages with the application.
74-
*
75-
* @remarks
76-
* By default, commands are visible. This method is only for global commands.
77-
* @param enabled - Whether the command should be enabled in direct messages
78-
* @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions}
79-
*/
80-
public setDMPermission(enabled: boolean | null | undefined) {
81-
// Assert the value matches the conditions
82-
validateDMPermission(enabled);
83-
84-
Reflect.set(this, 'dm_permission', enabled);
85-
86-
return this;
87-
}
88-
89-
/**
90-
* Sets whether this command is NSFW.
91-
*
92-
* @param nsfw - Whether this command is NSFW
93-
*/
94-
public setNSFW(nsfw = true) {
95-
// Assert the value matches the conditions
96-
validateNSFW(nsfw);
97-
Reflect.set(this, 'nsfw', nsfw);
98-
return this;
99-
}
100-
10115
/**
10216
* Adds a new subcommand group to this command.
10317
*
@@ -149,23 +63,4 @@ export class SharedSlashCommandSubcommands<
14963

15064
return this as unknown as TypeAfterAddingSubcommands;
15165
}
152-
153-
/**
154-
* Serializes this builder to API-compatible JSON data.
155-
*
156-
* @remarks
157-
* This method runs validations on the data before serializing it.
158-
* As such, it may throw an error if the data is invalid.
159-
*/
160-
public toJSON(): RESTPostAPIChatInputApplicationCommandsJSONBody {
161-
validateRequiredParameters(this.name, this.description, this.options);
162-
163-
validateLocalizationMap(this.name_localizations);
164-
validateLocalizationMap(this.description_localizations);
165-
166-
return {
167-
...this,
168-
options: this.options.map((option) => option.toJSON()),
169-
};
170-
}
17166
}

0 commit comments

Comments
 (0)