mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-19 04:53:30 +01:00
refactor: Don't return builders from API data (#7584)
* refactor: don't return builders from API data * Update packages/discord.js/src/structures/ActionRow.js Co-authored-by: Antonio Román <kyradiscord@gmail.com> * fix: circular dependency * fix: circular dependency pt.2 * chore: make requested changes * chore: bump dapi-types * chore: convert text input * chore: convert text input * feat: handle cases of unknown component types better * refactor: refactor modal to builder * feat: add #from for easy builder conversions * refactor: make requested changes * chore: make requested changes * style: fix linting error Co-authored-by: Antonio Román <kyradiscord@gmail.com> Co-authored-by: almeidx <almeidx@pm.me>
This commit is contained in:
@@ -1,13 +1,13 @@
|
|||||||
|
import { APIActionRowComponent, APIMessageActionRowComponent, ButtonStyle, ComponentType } from 'discord-api-types/v9';
|
||||||
import {
|
import {
|
||||||
APIActionRowComponent,
|
ActionRowBuilder,
|
||||||
APIActionRowComponentTypes,
|
ButtonBuilder,
|
||||||
APIMessageActionRowComponent,
|
createComponentBuilder,
|
||||||
ButtonStyle,
|
SelectMenuBuilder,
|
||||||
ComponentType,
|
SelectMenuOptionBuilder,
|
||||||
} from 'discord-api-types/v9';
|
} from '../../src';
|
||||||
import { ActionRow, ButtonComponent, createComponent, SelectMenuComponent, SelectMenuOption } from '../../src';
|
|
||||||
|
|
||||||
const rowWithButtonData: APIActionRowComponent<APIMessageComponent> = {
|
const rowWithButtonData: APIActionRowComponent<APIMessageActionRowComponent> = {
|
||||||
type: ComponentType.ActionRow,
|
type: ComponentType.ActionRow,
|
||||||
components: [
|
components: [
|
||||||
{
|
{
|
||||||
@@ -19,7 +19,7 @@ const rowWithButtonData: APIActionRowComponent<APIMessageComponent> = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const rowWithSelectMenuData: APIActionRowComponent<APIMessageComponent> = {
|
const rowWithSelectMenuData: APIActionRowComponent<APIMessageActionRowComponent> = {
|
||||||
type: ComponentType.ActionRow,
|
type: ComponentType.ActionRow,
|
||||||
components: [
|
components: [
|
||||||
{
|
{
|
||||||
@@ -44,8 +44,8 @@ const rowWithSelectMenuData: APIActionRowComponent<APIMessageComponent> = {
|
|||||||
describe('Action Row Components', () => {
|
describe('Action Row Components', () => {
|
||||||
describe('Assertion Tests', () => {
|
describe('Assertion Tests', () => {
|
||||||
test('GIVEN valid components THEN do not throw', () => {
|
test('GIVEN valid components THEN do not throw', () => {
|
||||||
expect(() => new ActionRow().addComponents(new ButtonComponent())).not.toThrowError();
|
expect(() => new ActionRowBuilder().addComponents(new ButtonBuilder())).not.toThrowError();
|
||||||
expect(() => new ActionRow().setComponents(new ButtonComponent())).not.toThrowError();
|
expect(() => new ActionRowBuilder().setComponents(new ButtonBuilder())).not.toThrowError();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN valid JSON input THEN valid JSON output is given', () => {
|
test('GIVEN valid JSON input THEN valid JSON output is given', () => {
|
||||||
@@ -78,13 +78,12 @@ describe('Action Row Components', () => {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(new ActionRow(actionRowData).toJSON()).toEqual(actionRowData);
|
expect(new ActionRowBuilder(actionRowData).toJSON()).toEqual(actionRowData);
|
||||||
expect(new ActionRow().toJSON()).toEqual({ type: ComponentType.ActionRow, components: [] });
|
expect(new ActionRowBuilder().toJSON()).toEqual({ type: ComponentType.ActionRow, components: [] });
|
||||||
expect(() => createComponent({ type: ComponentType.ActionRow, components: [] })).not.toThrowError();
|
expect(() => createComponentBuilder({ type: ComponentType.ActionRow, components: [] })).not.toThrowError();
|
||||||
expect(() => createComponent({ type: 42, components: [] })).toThrowError();
|
|
||||||
});
|
});
|
||||||
test('GIVEN valid builder options THEN valid JSON output is given', () => {
|
test('GIVEN valid builder options THEN valid JSON output is given', () => {
|
||||||
const rowWithButtonData: APIActionRowComponent<APIActionRowComponentTypes> = {
|
const rowWithButtonData: APIActionRowComponent<APIMessageActionRowComponent> = {
|
||||||
type: ComponentType.ActionRow,
|
type: ComponentType.ActionRow,
|
||||||
components: [
|
components: [
|
||||||
{
|
{
|
||||||
@@ -96,7 +95,7 @@ describe('Action Row Components', () => {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const rowWithSelectMenuData: APIActionRowComponent<APIActionRowComponentTypes> = {
|
const rowWithSelectMenuData: APIActionRowComponent<APIMessageActionRowComponent> = {
|
||||||
type: ComponentType.ActionRow,
|
type: ComponentType.ActionRow,
|
||||||
components: [
|
components: [
|
||||||
{
|
{
|
||||||
@@ -118,22 +117,24 @@ describe('Action Row Components', () => {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const button = new ButtonComponent().setLabel('test').setStyle(ButtonStyle.Primary).setCustomId('123');
|
expect(new ActionRowBuilder(rowWithButtonData).toJSON()).toEqual(rowWithButtonData);
|
||||||
const selectMenu = new SelectMenuComponent()
|
expect(new ActionRowBuilder(rowWithSelectMenuData).toJSON()).toEqual(rowWithSelectMenuData);
|
||||||
|
expect(new ActionRowBuilder().toJSON()).toEqual({ type: ComponentType.ActionRow, components: [] });
|
||||||
|
expect(() => createComponentBuilder({ type: ComponentType.ActionRow, components: [] })).not.toThrowError();
|
||||||
|
});
|
||||||
|
test('GIVEN valid builder options THEN valid JSON output is given', () => {
|
||||||
|
const button = new ButtonBuilder().setLabel('test').setStyle(ButtonStyle.Primary).setCustomId('123');
|
||||||
|
const selectMenu = new SelectMenuBuilder()
|
||||||
.setCustomId('1234')
|
.setCustomId('1234')
|
||||||
.setMaxValues(10)
|
.setMaxValues(10)
|
||||||
.setMinValues(12)
|
.setMinValues(12)
|
||||||
.setOptions(
|
.setOptions(
|
||||||
new SelectMenuOption().setLabel('one').setValue('one'),
|
new SelectMenuOptionBuilder().setLabel('one').setValue('one'),
|
||||||
new SelectMenuOption().setLabel('two').setValue('two'),
|
new SelectMenuOptionBuilder().setLabel('two').setValue('two'),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(new ActionRow().addComponents(button).toJSON()).toEqual(rowWithButtonData);
|
expect(new ActionRowBuilder().addComponents(button).toJSON()).toEqual(rowWithButtonData);
|
||||||
expect(new ActionRow().addComponents(selectMenu).toJSON()).toEqual(rowWithSelectMenuData);
|
expect(new ActionRowBuilder().addComponents(selectMenu).toJSON()).toEqual(rowWithSelectMenuData);
|
||||||
});
|
|
||||||
test('Given JSON data THEN builder is equal to it and itself', () => {
|
|
||||||
expect(new ActionRow(rowWithSelectMenuData).equals(rowWithSelectMenuData)).toBeTruthy();
|
|
||||||
expect(new ActionRow(rowWithButtonData).equals(new ActionRow(rowWithButtonData))).toBeTruthy();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import {
|
|||||||
ComponentType,
|
ComponentType,
|
||||||
} from 'discord-api-types/v9';
|
} from 'discord-api-types/v9';
|
||||||
import { buttonLabelValidator, buttonStyleValidator } from '../../src/components/Assertions';
|
import { buttonLabelValidator, buttonStyleValidator } from '../../src/components/Assertions';
|
||||||
import { ButtonComponent } from '../../src/components/button/Button';
|
import { ButtonBuilder } from '../../src/components/button/Button';
|
||||||
|
|
||||||
const buttonComponent = () => new ButtonComponent();
|
const buttonComponent = () => new ButtonBuilder();
|
||||||
|
|
||||||
const longStr =
|
const longStr =
|
||||||
'looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong';
|
'looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong';
|
||||||
@@ -119,7 +119,7 @@ describe('Button Components', () => {
|
|||||||
disabled: true,
|
disabled: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(new ButtonComponent(interactionData).toJSON()).toEqual(interactionData);
|
expect(new ButtonBuilder(interactionData).toJSON()).toEqual(interactionData);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
buttonComponent()
|
buttonComponent()
|
||||||
@@ -138,21 +138,9 @@ describe('Button Components', () => {
|
|||||||
url: 'https://google.com',
|
url: 'https://google.com',
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(new ButtonComponent(linkData).toJSON()).toEqual(linkData);
|
expect(new ButtonBuilder(linkData).toJSON()).toEqual(linkData);
|
||||||
|
|
||||||
expect(buttonComponent().setLabel(linkData.label).setDisabled(true).setURL(linkData.url));
|
expect(buttonComponent().setLabel(linkData.label).setDisabled(true).setURL(linkData.url));
|
||||||
});
|
});
|
||||||
test('Given JSON data THEN builder is equal to it and itself', () => {
|
|
||||||
const buttonData: APIButtonComponentWithCustomId = {
|
|
||||||
type: ComponentType.Button,
|
|
||||||
custom_id: 'test',
|
|
||||||
label: 'test',
|
|
||||||
style: ButtonStyle.Primary,
|
|
||||||
disabled: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(new ButtonComponent(buttonData).equals(buttonData)).toBeTruthy();
|
|
||||||
expect(new ButtonComponent(buttonData).equals(new ButtonComponent(buttonData))).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { APISelectMenuComponent, APISelectMenuOption, ComponentType } from 'discord-api-types/v9';
|
import { APISelectMenuComponent, APISelectMenuOption, ComponentType } from 'discord-api-types/v9';
|
||||||
import { SelectMenuComponent, SelectMenuOption } from '../../src/index';
|
import { SelectMenuBuilder, SelectMenuOptionBuilder } from '../../src/index';
|
||||||
|
|
||||||
const selectMenu = () => new SelectMenuComponent();
|
const selectMenu = () => new SelectMenuBuilder();
|
||||||
const selectMenuOption = () => new SelectMenuOption();
|
const selectMenuOption = () => new SelectMenuOptionBuilder();
|
||||||
|
|
||||||
const longStr = 'a'.repeat(256);
|
const longStr = 'a'.repeat(256);
|
||||||
|
|
||||||
@@ -44,8 +44,8 @@ describe('Select Menu Components', () => {
|
|||||||
.setEmoji({ name: 'test' })
|
.setEmoji({ name: 'test' })
|
||||||
.setDescription('description');
|
.setDescription('description');
|
||||||
expect(() => selectMenu().addOptions(option)).not.toThrowError();
|
expect(() => selectMenu().addOptions(option)).not.toThrowError();
|
||||||
expect(() => selectMenu().setOptions([option])).not.toThrowError();
|
expect(() => selectMenu().setOptions(option)).not.toThrowError();
|
||||||
expect(() => selectMenu().setOptions([{ label: 'test', value: 'test' }])).not.toThrowError();
|
expect(() => selectMenu().setOptions({ label: 'test', value: 'test' })).not.toThrowError();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN invalid inputs THEN Select Menu does throw', () => {
|
test('GIVEN invalid inputs THEN Select Menu does throw', () => {
|
||||||
@@ -70,16 +70,11 @@ describe('Select Menu Components', () => {
|
|||||||
|
|
||||||
test('GIVEN valid JSON input THEN valid JSON history is correct', () => {
|
test('GIVEN valid JSON input THEN valid JSON history is correct', () => {
|
||||||
expect(
|
expect(
|
||||||
new SelectMenuComponent(selectMenuDataWithoutOptions)
|
new SelectMenuBuilder(selectMenuDataWithoutOptions)
|
||||||
.addOptions(new SelectMenuOption(selectMenuOptionData))
|
.addOptions(new SelectMenuOptionBuilder(selectMenuOptionData))
|
||||||
.toJSON(),
|
.toJSON(),
|
||||||
).toEqual(selectMenuData);
|
).toEqual(selectMenuData);
|
||||||
expect(new SelectMenuOption(selectMenuOptionData).toJSON()).toEqual(selectMenuOptionData);
|
expect(new SelectMenuOptionBuilder(selectMenuOptionData).toJSON()).toEqual(selectMenuOptionData);
|
||||||
});
|
|
||||||
|
|
||||||
test('Given JSON data THEN builder is equal to it and itself', () => {
|
|
||||||
expect(new SelectMenuComponent(selectMenuData).equals(selectMenuData)).toBeTruthy();
|
|
||||||
expect(new SelectMenuComponent(selectMenuData).equals(new SelectMenuComponent(selectMenuData))).toBeTruthy();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import {
|
|||||||
valueValidator,
|
valueValidator,
|
||||||
textInputStyleValidator,
|
textInputStyleValidator,
|
||||||
} from '../../src/components/textInput/Assertions';
|
} from '../../src/components/textInput/Assertions';
|
||||||
import { TextInputComponent } from '../../src/components/textInput/TextInput';
|
import { TextInputBuilder } from '../../src/components/textInput/TextInput';
|
||||||
|
|
||||||
const superLongStr = 'a'.repeat(5000);
|
const superLongStr = 'a'.repeat(5000);
|
||||||
|
|
||||||
const textInputComponent = () => new TextInputComponent();
|
const textInputComponent = () => new TextInputBuilder();
|
||||||
|
|
||||||
describe('Text Input Components', () => {
|
describe('Text Input Components', () => {
|
||||||
describe('Assertion Tests', () => {
|
describe('Assertion Tests', () => {
|
||||||
@@ -109,7 +109,7 @@ describe('Text Input Components', () => {
|
|||||||
style: TextInputStyle.Paragraph,
|
style: TextInputStyle.Paragraph,
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(new TextInputComponent(textInputData).toJSON()).toEqual(textInputData);
|
expect(new TextInputBuilder(textInputData).toJSON()).toEqual(textInputData);
|
||||||
expect(
|
expect(
|
||||||
textInputComponent()
|
textInputComponent()
|
||||||
.setCustomId(textInputData.custom_id)
|
.setCustomId(textInputData.custom_id)
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
import { APIModalInteractionResponseCallbackData, ComponentType, TextInputStyle } from 'discord-api-types/v9';
|
import { APIModalInteractionResponseCallbackData, ComponentType, TextInputStyle } from 'discord-api-types/v9';
|
||||||
import { ActionRow, ButtonComponent, Modal, ModalActionRowComponent, TextInputComponent } from '../../src';
|
import {
|
||||||
|
ActionRowBuilder,
|
||||||
|
ButtonBuilder,
|
||||||
|
ModalBuilder,
|
||||||
|
ModalActionRowComponentBuilder,
|
||||||
|
TextInputBuilder,
|
||||||
|
} from '../../src';
|
||||||
import {
|
import {
|
||||||
componentsValidator,
|
componentsValidator,
|
||||||
titleValidator,
|
titleValidator,
|
||||||
validateRequiredParameters,
|
validateRequiredParameters,
|
||||||
} from '../../src/interactions/modals/Assertions';
|
} from '../../src/interactions/modals/Assertions';
|
||||||
|
|
||||||
const modal = () => new Modal();
|
const modal = () => new ModalBuilder();
|
||||||
|
|
||||||
describe('Modals', () => {
|
describe('Modals', () => {
|
||||||
describe('Assertion Tests', () => {
|
describe('Assertion Tests', () => {
|
||||||
@@ -19,33 +25,37 @@ describe('Modals', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN valid components THEN validator does not throw', () => {
|
test('GIVEN valid components THEN validator does not throw', () => {
|
||||||
expect(() => componentsValidator.parse([new ActionRow(), new ActionRow()])).not.toThrowError();
|
expect(() => componentsValidator.parse([new ActionRowBuilder(), new ActionRowBuilder()])).not.toThrowError();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN invalid components THEN validator does throw', () => {
|
test('GIVEN invalid components THEN validator does throw', () => {
|
||||||
expect(() => componentsValidator.parse([new ButtonComponent(), new TextInputComponent()])).toThrowError();
|
expect(() => componentsValidator.parse([new ButtonBuilder(), new TextInputBuilder()])).toThrowError();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN valid required parameters THEN validator does not throw', () => {
|
test('GIVEN valid required parameters THEN validator does not throw', () => {
|
||||||
expect(() => validateRequiredParameters('123', 'title', [new ActionRow(), new ActionRow()])).not.toThrowError();
|
expect(() =>
|
||||||
|
validateRequiredParameters('123', 'title', [new ActionRowBuilder(), new ActionRowBuilder()]),
|
||||||
|
).not.toThrowError();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN invalid required parameters THEN validator does throw', () => {
|
test('GIVEN invalid required parameters THEN validator does throw', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
validateRequiredParameters('123', undefined, [new ActionRow(), new ButtonComponent()]),
|
validateRequiredParameters('123', undefined, [new ActionRowBuilder(), new ButtonBuilder()]),
|
||||||
).toThrowError();
|
).toThrowError();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN valid fields THEN builder does not throw', () => {
|
test('GIVEN valid fields THEN builder does not throw', () => {
|
||||||
expect(() => modal().setTitle('test').setCustomId('foobar').setComponents(new ActionRow())).not.toThrowError();
|
expect(() =>
|
||||||
|
modal().setTitle('test').setCustomId('foobar').setComponents(new ActionRowBuilder()),
|
||||||
|
).not.toThrowError();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN invalid fields THEN builder does throw', () => {
|
test('GIVEN invalid fields THEN builder does throw', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
modal().setTitle('test').setCustomId('foobar').setComponents([new ActionRow()]).toJSON(),
|
modal().setTitle('test').setCustomId('foobar').setComponents([new ActionRowBuilder()]).toJSON(),
|
||||||
).toThrowError();
|
).toThrowError();
|
||||||
expect(() => modal().setTitle('test').setCustomId('foobar').toJSON()).toThrowError();
|
expect(() => modal().setTitle('test').setCustomId('foobar').toJSON()).toThrowError();
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
@@ -71,15 +81,15 @@ describe('Modals', () => {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(new Modal(modalData).toJSON()).toEqual(modalData);
|
expect(new ModalBuilder(modalData).toJSON()).toEqual(modalData);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
modal()
|
modal()
|
||||||
.setTitle(modalData.title)
|
.setTitle(modalData.title)
|
||||||
.setCustomId('custom id')
|
.setCustomId('custom id')
|
||||||
.setComponents(
|
.setComponents(
|
||||||
new ActionRow<ModalActionRowComponent>().addComponents(
|
new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(
|
||||||
new TextInputComponent().setCustomId('custom id').setLabel('label').setStyle(TextInputStyle.Paragraph),
|
new TextInputBuilder().setCustomId('custom id').setLabel('label').setStyle(TextInputStyle.Paragraph),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toJSON(),
|
.toJSON(),
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { Embed } from '../../src';
|
import { EmbedBuilder, embedLength } from '../../src';
|
||||||
|
|
||||||
const alpha = 'abcdefghijklmnopqrstuvwxyz';
|
const alpha = 'abcdefghijklmnopqrstuvwxyz';
|
||||||
|
|
||||||
describe('Embed', () => {
|
describe('Embed', () => {
|
||||||
describe('Embed getters', () => {
|
describe('Embed getters', () => {
|
||||||
test('GIVEN an embed with specific amount of characters THEN returns amount of characters', () => {
|
test('GIVEN an embed with specific amount of characters THEN returns amount of characters', () => {
|
||||||
const embed = new Embed({
|
const embed = new EmbedBuilder({
|
||||||
title: alpha,
|
title: alpha,
|
||||||
description: alpha,
|
description: alpha,
|
||||||
fields: [{ name: alpha, value: alpha }],
|
fields: [{ name: alpha, value: alpha }],
|
||||||
@@ -13,38 +13,38 @@ describe('Embed', () => {
|
|||||||
footer: { text: alpha },
|
footer: { text: alpha },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(embed.length).toBe(alpha.length * 6);
|
expect(embedLength(embed.data)).toBe(alpha.length * 6);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with zero characters THEN returns amount of characters', () => {
|
test('GIVEN an embed with zero characters THEN returns amount of characters', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
expect(embed.length).toBe(0);
|
expect(embedLength(embed.data)).toBe(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Embed title', () => {
|
describe('Embed title', () => {
|
||||||
test('GIVEN an embed with a pre-defined title THEN return valid toJSON data', () => {
|
test('GIVEN an embed with a pre-defined title THEN return valid toJSON data', () => {
|
||||||
const embed = new Embed({ title: 'foo' });
|
const embed = new EmbedBuilder({ title: 'foo' });
|
||||||
expect(embed.toJSON()).toStrictEqual({ title: 'foo' });
|
expect(embed.toJSON()).toStrictEqual({ title: 'foo' });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed using Embed#setTitle THEN return valid toJSON data', () => {
|
test('GIVEN an embed using Embed#setTitle THEN return valid toJSON data', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
embed.setTitle('foo');
|
embed.setTitle('foo');
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ title: 'foo' });
|
expect(embed.toJSON()).toStrictEqual({ title: 'foo' });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with a pre-defined title THEN unset title THEN return valid toJSON data', () => {
|
test('GIVEN an embed with a pre-defined title THEN unset title THEN return valid toJSON data', () => {
|
||||||
const embed = new Embed({ title: 'foo' });
|
const embed = new EmbedBuilder({ title: 'foo' });
|
||||||
embed.setTitle(null);
|
embed.setTitle(null);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ title: undefined });
|
expect(embed.toJSON()).toStrictEqual({ title: undefined });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with an invalid title THEN throws error', () => {
|
test('GIVEN an embed with an invalid title THEN throws error', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
expect(() => embed.setTitle('a'.repeat(257))).toThrowError();
|
expect(() => embed.setTitle('a'.repeat(257))).toThrowError();
|
||||||
});
|
});
|
||||||
@@ -52,26 +52,26 @@ describe('Embed', () => {
|
|||||||
|
|
||||||
describe('Embed description', () => {
|
describe('Embed description', () => {
|
||||||
test('GIVEN an embed with a pre-defined description THEN return valid toJSON data', () => {
|
test('GIVEN an embed with a pre-defined description THEN return valid toJSON data', () => {
|
||||||
const embed = new Embed({ description: 'foo' });
|
const embed = new EmbedBuilder({ description: 'foo' });
|
||||||
expect(embed.toJSON()).toStrictEqual({ description: 'foo' });
|
expect(embed.toJSON()).toStrictEqual({ description: 'foo' });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed using Embed#setDescription THEN return valid toJSON data', () => {
|
test('GIVEN an embed using Embed#setDescription THEN return valid toJSON data', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
embed.setDescription('foo');
|
embed.setDescription('foo');
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ description: 'foo' });
|
expect(embed.toJSON()).toStrictEqual({ description: 'foo' });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with a pre-defined description THEN unset description THEN return valid toJSON data', () => {
|
test('GIVEN an embed with a pre-defined description THEN unset description THEN return valid toJSON data', () => {
|
||||||
const embed = new Embed({ description: 'foo' });
|
const embed = new EmbedBuilder({ description: 'foo' });
|
||||||
embed.setDescription(null);
|
embed.setDescription(null);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ description: undefined });
|
expect(embed.toJSON()).toStrictEqual({ description: undefined });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with an invalid description THEN throws error', () => {
|
test('GIVEN an embed with an invalid description THEN throws error', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
expect(() => embed.setDescription('a'.repeat(4097))).toThrowError();
|
expect(() => embed.setDescription('a'.repeat(4097))).toThrowError();
|
||||||
});
|
});
|
||||||
@@ -79,14 +79,14 @@ describe('Embed', () => {
|
|||||||
|
|
||||||
describe('Embed URL', () => {
|
describe('Embed URL', () => {
|
||||||
test('GIVEN an embed with a pre-defined url THEN returns valid toJSON data', () => {
|
test('GIVEN an embed with a pre-defined url THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed({ url: 'https://discord.js.org/' });
|
const embed = new EmbedBuilder({ url: 'https://discord.js.org/' });
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
url: 'https://discord.js.org/',
|
url: 'https://discord.js.org/',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed using Embed#setURL THEN returns valid toJSON data', () => {
|
test('GIVEN an embed using Embed#setURL THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
embed.setURL('https://discord.js.org/');
|
embed.setURL('https://discord.js.org/');
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
@@ -95,14 +95,14 @@ describe('Embed', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with a pre-defined title THEN unset title THEN return valid toJSON data', () => {
|
test('GIVEN an embed with a pre-defined title THEN unset title THEN return valid toJSON data', () => {
|
||||||
const embed = new Embed({ url: 'https://discord.js.org' });
|
const embed = new EmbedBuilder({ url: 'https://discord.js.org' });
|
||||||
embed.setURL(null);
|
embed.setURL(null);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ url: undefined });
|
expect(embed.toJSON()).toStrictEqual({ url: undefined });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with an invalid URL THEN throws error', () => {
|
test('GIVEN an embed with an invalid URL THEN throws error', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
expect(() => embed.setURL('owo')).toThrowError();
|
expect(() => embed.setURL('owo')).toThrowError();
|
||||||
});
|
});
|
||||||
@@ -110,24 +110,24 @@ describe('Embed', () => {
|
|||||||
|
|
||||||
describe('Embed Color', () => {
|
describe('Embed Color', () => {
|
||||||
test('GIVEN an embed with a pre-defined color THEN returns valid toJSON data', () => {
|
test('GIVEN an embed with a pre-defined color THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed({ color: 0xff0000 });
|
const embed = new EmbedBuilder({ color: 0xff0000 });
|
||||||
expect(embed.toJSON()).toStrictEqual({ color: 0xff0000 });
|
expect(embed.toJSON()).toStrictEqual({ color: 0xff0000 });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed using Embed#setColor THEN returns valid toJSON data', () => {
|
test('GIVEN an embed using Embed#setColor THEN returns valid toJSON data', () => {
|
||||||
expect(new Embed().setColor(0xff0000).toJSON()).toStrictEqual({ color: 0xff0000 });
|
expect(new EmbedBuilder().setColor(0xff0000).toJSON()).toStrictEqual({ color: 0xff0000 });
|
||||||
expect(new Embed().setColor([242, 66, 245]).toJSON()).toStrictEqual({ color: 0xf242f5 });
|
expect(new EmbedBuilder().setColor([242, 66, 245]).toJSON()).toStrictEqual({ color: 0xf242f5 });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with a pre-defined color THEN unset color THEN return valid toJSON data', () => {
|
test('GIVEN an embed with a pre-defined color THEN unset color THEN return valid toJSON data', () => {
|
||||||
const embed = new Embed({ color: 0xff0000 });
|
const embed = new EmbedBuilder({ color: 0xff0000 });
|
||||||
embed.setColor(null);
|
embed.setColor(null);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ color: undefined });
|
expect(embed.toJSON()).toStrictEqual({ color: undefined });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with an invalid color THEN throws error', () => {
|
test('GIVEN an embed with an invalid color THEN throws error', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
expect(() => embed.setColor('RED')).toThrowError();
|
expect(() => embed.setColor('RED')).toThrowError();
|
||||||
@@ -141,33 +141,33 @@ describe('Embed', () => {
|
|||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
|
||||||
test('GIVEN an embed with a pre-defined timestamp THEN returns valid toJSON data', () => {
|
test('GIVEN an embed with a pre-defined timestamp THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed({ timestamp: now.toISOString() });
|
const embed = new EmbedBuilder({ timestamp: now.toISOString() });
|
||||||
expect(embed.toJSON()).toStrictEqual({ timestamp: now.toISOString() });
|
expect(embed.toJSON()).toStrictEqual({ timestamp: now.toISOString() });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('given an embed using Embed#setTimestamp (with Date) THEN returns valid toJSON data', () => {
|
test('given an embed using Embed#setTimestamp (with Date) THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
embed.setTimestamp(now);
|
embed.setTimestamp(now);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ timestamp: now.toISOString() });
|
expect(embed.toJSON()).toStrictEqual({ timestamp: now.toISOString() });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed using Embed#setTimestamp (with int) THEN returns valid toJSON data', () => {
|
test('GIVEN an embed using Embed#setTimestamp (with int) THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
embed.setTimestamp(now.getTime());
|
embed.setTimestamp(now.getTime());
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ timestamp: now.toISOString() });
|
expect(embed.toJSON()).toStrictEqual({ timestamp: now.toISOString() });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed using Embed#setTimestamp (default) THEN returns valid toJSON data', () => {
|
test('GIVEN an embed using Embed#setTimestamp (default) THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
embed.setTimestamp();
|
embed.setTimestamp();
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ timestamp: embed.timestamp });
|
expect(embed.toJSON()).toStrictEqual({ timestamp: embed.data.timestamp });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with a pre-defined timestamp THEN unset timestamp THEN return valid toJSON data', () => {
|
test('GIVEN an embed with a pre-defined timestamp THEN unset timestamp THEN return valid toJSON data', () => {
|
||||||
const embed = new Embed({ timestamp: now.toISOString() });
|
const embed = new EmbedBuilder({ timestamp: now.toISOString() });
|
||||||
embed.setTimestamp(null);
|
embed.setTimestamp(null);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ timestamp: undefined });
|
expect(embed.toJSON()).toStrictEqual({ timestamp: undefined });
|
||||||
@@ -176,14 +176,14 @@ describe('Embed', () => {
|
|||||||
|
|
||||||
describe('Embed Thumbnail', () => {
|
describe('Embed Thumbnail', () => {
|
||||||
test('GIVEN an embed with a pre-defined thumbnail THEN returns valid toJSON data', () => {
|
test('GIVEN an embed with a pre-defined thumbnail THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed({ thumbnail: { url: 'https://discord.js.org/static/logo.svg' } });
|
const embed = new EmbedBuilder({ thumbnail: { url: 'https://discord.js.org/static/logo.svg' } });
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
thumbnail: { url: 'https://discord.js.org/static/logo.svg' },
|
thumbnail: { url: 'https://discord.js.org/static/logo.svg' },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed using Embed#setThumbnail THEN returns valid toJSON data', () => {
|
test('GIVEN an embed using Embed#setThumbnail THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
embed.setThumbnail('https://discord.js.org/static/logo.svg');
|
embed.setThumbnail('https://discord.js.org/static/logo.svg');
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
@@ -192,14 +192,14 @@ describe('Embed', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with a pre-defined thumbnail THEN unset thumbnail THEN return valid toJSON data', () => {
|
test('GIVEN an embed with a pre-defined thumbnail THEN unset thumbnail THEN return valid toJSON data', () => {
|
||||||
const embed = new Embed({ thumbnail: { url: 'https://discord.js.org/static/logo.svg' } });
|
const embed = new EmbedBuilder({ thumbnail: { url: 'https://discord.js.org/static/logo.svg' } });
|
||||||
embed.setThumbnail(null);
|
embed.setThumbnail(null);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ thumbnail: undefined });
|
expect(embed.toJSON()).toStrictEqual({ thumbnail: undefined });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with an invalid thumbnail THEN throws error', () => {
|
test('GIVEN an embed with an invalid thumbnail THEN throws error', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
expect(() => embed.setThumbnail('owo')).toThrowError();
|
expect(() => embed.setThumbnail('owo')).toThrowError();
|
||||||
});
|
});
|
||||||
@@ -207,14 +207,14 @@ describe('Embed', () => {
|
|||||||
|
|
||||||
describe('Embed Image', () => {
|
describe('Embed Image', () => {
|
||||||
test('GIVEN an embed with a pre-defined image THEN returns valid toJSON data', () => {
|
test('GIVEN an embed with a pre-defined image THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed({ image: { url: 'https://discord.js.org/static/logo.svg' } });
|
const embed = new EmbedBuilder({ image: { url: 'https://discord.js.org/static/logo.svg' } });
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
image: { url: 'https://discord.js.org/static/logo.svg' },
|
image: { url: 'https://discord.js.org/static/logo.svg' },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed using Embed#setImage THEN returns valid toJSON data', () => {
|
test('GIVEN an embed using Embed#setImage THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
embed.setImage('https://discord.js.org/static/logo.svg');
|
embed.setImage('https://discord.js.org/static/logo.svg');
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
@@ -223,14 +223,14 @@ describe('Embed', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with a pre-defined image THEN unset image THEN return valid toJSON data', () => {
|
test('GIVEN an embed with a pre-defined image THEN unset image THEN return valid toJSON data', () => {
|
||||||
const embed = new Embed({ image: { url: 'https://discord.js/org/static/logo.svg' } });
|
const embed = new EmbedBuilder({ image: { url: 'https://discord.js/org/static/logo.svg' } });
|
||||||
embed.setImage(null);
|
embed.setImage(null);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ image: undefined });
|
expect(embed.toJSON()).toStrictEqual({ image: undefined });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with an invalid image THEN throws error', () => {
|
test('GIVEN an embed with an invalid image THEN throws error', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
expect(() => embed.setImage('owo')).toThrowError();
|
expect(() => embed.setImage('owo')).toThrowError();
|
||||||
});
|
});
|
||||||
@@ -238,7 +238,7 @@ describe('Embed', () => {
|
|||||||
|
|
||||||
describe('Embed Author', () => {
|
describe('Embed Author', () => {
|
||||||
test('GIVEN an embed with a pre-defined author THEN returns valid toJSON data', () => {
|
test('GIVEN an embed with a pre-defined author THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed({
|
const embed = new EmbedBuilder({
|
||||||
author: { name: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg', url: 'https://discord.js.org' },
|
author: { name: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg', url: 'https://discord.js.org' },
|
||||||
});
|
});
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
@@ -247,7 +247,7 @@ describe('Embed', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed using Embed#setAuthor THEN returns valid toJSON data', () => {
|
test('GIVEN an embed using Embed#setAuthor THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
embed.setAuthor({
|
embed.setAuthor({
|
||||||
name: 'Wumpus',
|
name: 'Wumpus',
|
||||||
iconURL: 'https://discord.js.org/static/logo.svg',
|
iconURL: 'https://discord.js.org/static/logo.svg',
|
||||||
@@ -260,7 +260,7 @@ describe('Embed', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with a pre-defined author THEN unset author THEN return valid toJSON data', () => {
|
test('GIVEN an embed with a pre-defined author THEN unset author THEN return valid toJSON data', () => {
|
||||||
const embed = new Embed({
|
const embed = new EmbedBuilder({
|
||||||
author: { name: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg', url: 'https://discord.js.org' },
|
author: { name: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg', url: 'https://discord.js.org' },
|
||||||
});
|
});
|
||||||
embed.setAuthor(null);
|
embed.setAuthor(null);
|
||||||
@@ -269,7 +269,7 @@ describe('Embed', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with an invalid author name THEN throws error', () => {
|
test('GIVEN an embed with an invalid author name THEN throws error', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
expect(() => embed.setAuthor({ name: 'a'.repeat(257) })).toThrowError();
|
expect(() => embed.setAuthor({ name: 'a'.repeat(257) })).toThrowError();
|
||||||
});
|
});
|
||||||
@@ -277,7 +277,7 @@ describe('Embed', () => {
|
|||||||
|
|
||||||
describe('Embed Footer', () => {
|
describe('Embed Footer', () => {
|
||||||
test('GIVEN an embed with a pre-defined footer THEN returns valid toJSON data', () => {
|
test('GIVEN an embed with a pre-defined footer THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed({
|
const embed = new EmbedBuilder({
|
||||||
footer: { text: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg' },
|
footer: { text: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg' },
|
||||||
});
|
});
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
@@ -286,7 +286,7 @@ describe('Embed', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed using Embed#setAuthor THEN returns valid toJSON data', () => {
|
test('GIVEN an embed using Embed#setAuthor THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
embed.setFooter({ text: 'Wumpus', iconURL: 'https://discord.js.org/static/logo.svg' });
|
embed.setFooter({ text: 'Wumpus', iconURL: 'https://discord.js.org/static/logo.svg' });
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
@@ -295,14 +295,16 @@ describe('Embed', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with a pre-defined footer THEN unset footer THEN return valid toJSON data', () => {
|
test('GIVEN an embed with a pre-defined footer THEN unset footer THEN return valid toJSON data', () => {
|
||||||
const embed = new Embed({ footer: { text: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg' } });
|
const embed = new EmbedBuilder({
|
||||||
|
footer: { text: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg' },
|
||||||
|
});
|
||||||
embed.setFooter(null);
|
embed.setFooter(null);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ footer: undefined });
|
expect(embed.toJSON()).toStrictEqual({ footer: undefined });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with invalid footer text THEN throws error', () => {
|
test('GIVEN an embed with invalid footer text THEN throws error', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
expect(() => embed.setFooter({ text: 'a'.repeat(2049) })).toThrowError();
|
expect(() => embed.setFooter({ text: 'a'.repeat(2049) })).toThrowError();
|
||||||
});
|
});
|
||||||
@@ -310,7 +312,7 @@ describe('Embed', () => {
|
|||||||
|
|
||||||
describe('Embed Fields', () => {
|
describe('Embed Fields', () => {
|
||||||
test('GIVEN an embed with a pre-defined field THEN returns valid toJSON data', () => {
|
test('GIVEN an embed with a pre-defined field THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed({
|
const embed = new EmbedBuilder({
|
||||||
fields: [{ name: 'foo', value: 'bar' }],
|
fields: [{ name: 'foo', value: 'bar' }],
|
||||||
});
|
});
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
@@ -319,7 +321,7 @@ describe('Embed', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed using Embed#addFields THEN returns valid toJSON data', () => {
|
test('GIVEN an embed using Embed#addFields THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
embed.addFields({ name: 'foo', value: 'bar' });
|
embed.addFields({ name: 'foo', value: 'bar' });
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
@@ -328,7 +330,7 @@ describe('Embed', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed using Embed#spliceFields THEN returns valid toJSON data', () => {
|
test('GIVEN an embed using Embed#spliceFields THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
embed.addFields({ name: 'foo', value: 'bar' }, { name: 'foo', value: 'baz' });
|
embed.addFields({ name: 'foo', value: 'bar' }, { name: 'foo', value: 'baz' });
|
||||||
|
|
||||||
expect(embed.spliceFields(0, 1).toJSON()).toStrictEqual({
|
expect(embed.spliceFields(0, 1).toJSON()).toStrictEqual({
|
||||||
@@ -337,7 +339,7 @@ describe('Embed', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed using Embed#spliceFields THEN returns valid toJSON data', () => {
|
test('GIVEN an embed using Embed#spliceFields THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
embed.addFields(...Array.from({ length: 23 }, () => ({ name: 'foo', value: 'bar' })));
|
embed.addFields(...Array.from({ length: 23 }, () => ({ name: 'foo', value: 'bar' })));
|
||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
@@ -346,7 +348,7 @@ describe('Embed', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed using Embed#spliceFields that adds additional fields resulting in fields > 25 THEN throws error', () => {
|
test('GIVEN an embed using Embed#spliceFields that adds additional fields resulting in fields > 25 THEN throws error', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
embed.addFields(...Array.from({ length: 23 }, () => ({ name: 'foo', value: 'bar' })));
|
embed.addFields(...Array.from({ length: 23 }, () => ({ name: 'foo', value: 'bar' })));
|
||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
@@ -355,7 +357,7 @@ describe('Embed', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed using Embed#setFields THEN returns valid toJSON data', () => {
|
test('GIVEN an embed using Embed#setFields THEN returns valid toJSON data', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
embed.setFields(...Array.from({ length: 25 }, () => ({ name: 'foo', value: 'bar' }))),
|
embed.setFields(...Array.from({ length: 25 }, () => ({ name: 'foo', value: 'bar' }))),
|
||||||
@@ -363,7 +365,7 @@ describe('Embed', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed using Embed#setFields that sets more than 25 fields THEN throws error', () => {
|
test('GIVEN an embed using Embed#setFields that sets more than 25 fields THEN throws error', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
embed.setFields(...Array.from({ length: 26 }, () => ({ name: 'foo', value: 'bar' }))),
|
embed.setFields(...Array.from({ length: 26 }, () => ({ name: 'foo', value: 'bar' }))),
|
||||||
@@ -372,7 +374,7 @@ describe('Embed', () => {
|
|||||||
|
|
||||||
describe('GIVEN invalid field amount THEN throws error', () => {
|
describe('GIVEN invalid field amount THEN throws error', () => {
|
||||||
test('', () => {
|
test('', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
embed.addFields(...Array.from({ length: 26 }, () => ({ name: 'foo', value: 'bar' }))),
|
embed.addFields(...Array.from({ length: 26 }, () => ({ name: 'foo', value: 'bar' }))),
|
||||||
@@ -382,7 +384,7 @@ describe('Embed', () => {
|
|||||||
|
|
||||||
describe('GIVEN invalid field name THEN throws error', () => {
|
describe('GIVEN invalid field name THEN throws error', () => {
|
||||||
test('', () => {
|
test('', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
expect(() => embed.addFields({ name: '', value: 'bar' })).toThrowError();
|
expect(() => embed.addFields({ name: '', value: 'bar' })).toThrowError();
|
||||||
});
|
});
|
||||||
@@ -390,7 +392,7 @@ describe('Embed', () => {
|
|||||||
|
|
||||||
describe('GIVEN invalid field name length THEN throws error', () => {
|
describe('GIVEN invalid field name length THEN throws error', () => {
|
||||||
test('', () => {
|
test('', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
expect(() => embed.addFields({ name: 'a'.repeat(257), value: 'bar' })).toThrowError();
|
expect(() => embed.addFields({ name: 'a'.repeat(257), value: 'bar' })).toThrowError();
|
||||||
});
|
});
|
||||||
@@ -398,7 +400,7 @@ describe('Embed', () => {
|
|||||||
|
|
||||||
describe('GIVEN invalid field value length THEN throws error', () => {
|
describe('GIVEN invalid field value length THEN throws error', () => {
|
||||||
test('', () => {
|
test('', () => {
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
expect(() => embed.addFields({ name: '', value: 'a'.repeat(1025) })).toThrowError();
|
expect(() => embed.addFields({ name: '', value: 'a'.repeat(1025) })).toThrowError();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,26 +1,29 @@
|
|||||||
import {
|
import {
|
||||||
APIActionRowComponent,
|
type APIActionRowComponent,
|
||||||
|
ComponentType,
|
||||||
APIMessageActionRowComponent,
|
APIMessageActionRowComponent,
|
||||||
APIModalActionRowComponent,
|
APIModalActionRowComponent,
|
||||||
ComponentType,
|
|
||||||
} from 'discord-api-types/v9';
|
} from 'discord-api-types/v9';
|
||||||
import type { ButtonComponent, SelectMenuComponent, TextInputComponent } from '../index';
|
import type { ButtonBuilder, SelectMenuBuilder, TextInputBuilder } from '..';
|
||||||
import { Component } from './Component';
|
import { ComponentBuilder } from './Component';
|
||||||
import { createComponent } from './Components';
|
import { createComponentBuilder } from './Components';
|
||||||
import isEqual from 'fast-deep-equal';
|
|
||||||
|
|
||||||
export type MessageComponent = MessageActionRowComponent | ActionRow<MessageActionRowComponent>;
|
export type MessageComponentBuilder =
|
||||||
export type ModalComponent = ModalActionRowComponent | ActionRow<ModalActionRowComponent>;
|
| MessageActionRowComponentBuilder
|
||||||
|
| ActionRowBuilder<MessageActionRowComponentBuilder>;
|
||||||
|
export type ModalComponentBuilder = ModalActionRowComponentBuilder | ActionRowBuilder<ModalActionRowComponentBuilder>;
|
||||||
|
|
||||||
export type MessageActionRowComponent = ButtonComponent | SelectMenuComponent;
|
export type MessageActionRowComponentBuilder = ButtonBuilder | SelectMenuBuilder;
|
||||||
export type ModalActionRowComponent = TextInputComponent;
|
export type ModalActionRowComponentBuilder = TextInputBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an action row component
|
* Represents an action row component
|
||||||
*/
|
*/
|
||||||
export class ActionRow<
|
export class ActionRowBuilder<
|
||||||
T extends ModalActionRowComponent | MessageActionRowComponent = ModalActionRowComponent | MessageActionRowComponent,
|
T extends MessageActionRowComponentBuilder | ModalActionRowComponentBuilder =
|
||||||
> extends Component<
|
| MessageActionRowComponentBuilder
|
||||||
|
| ModalActionRowComponentBuilder,
|
||||||
|
> extends ComponentBuilder<
|
||||||
Omit<
|
Omit<
|
||||||
Partial<APIActionRowComponent<APIMessageActionRowComponent | APIModalActionRowComponent>> & {
|
Partial<APIActionRowComponent<APIMessageActionRowComponent | APIModalActionRowComponent>> & {
|
||||||
type: ComponentType.ActionRow;
|
type: ComponentType.ActionRow;
|
||||||
@@ -31,14 +34,14 @@ export class ActionRow<
|
|||||||
/**
|
/**
|
||||||
* The components within this action row
|
* The components within this action row
|
||||||
*/
|
*/
|
||||||
public readonly components: T[];
|
private readonly components: T[];
|
||||||
|
|
||||||
public constructor({
|
public constructor({
|
||||||
components,
|
components,
|
||||||
...data
|
...data
|
||||||
}: Partial<APIActionRowComponent<APIMessageActionRowComponent | APIModalActionRowComponent>> = {}) {
|
}: Partial<APIActionRowComponent<APIMessageActionRowComponent | APIModalActionRowComponent>> = {}) {
|
||||||
super({ type: ComponentType.ActionRow, ...data });
|
super({ type: ComponentType.ActionRow, ...data });
|
||||||
this.components = (components?.map((c) => createComponent(c)) ?? []) as T[];
|
this.components = (components?.map((c) => createComponentBuilder(c)) ?? []) as T[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,14 +69,4 @@ export class ActionRow<
|
|||||||
components: this.components.map((component) => component.toJSON()) as ReturnType<T['toJSON']>[],
|
components: this.components.map((component) => component.toJSON()) as ReturnType<T['toJSON']>[],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public equals(other: APIActionRowComponent<APIMessageActionRowComponent | APIModalActionRowComponent> | ActionRow) {
|
|
||||||
if (other instanceof ActionRow) {
|
|
||||||
return isEqual(other.data, this.data) && isEqual(other.components, this.components);
|
|
||||||
}
|
|
||||||
return isEqual(other, {
|
|
||||||
...this.data,
|
|
||||||
components: this.components.map((component) => component.toJSON()),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { APIMessageComponentEmoji, ButtonStyle } from 'discord-api-types/v9';
|
import { APIMessageComponentEmoji, ButtonStyle } from 'discord-api-types/v9';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import type { SelectMenuOption } from './selectMenu/SelectMenuOption';
|
import type { SelectMenuOptionBuilder } from './selectMenu/SelectMenuOption';
|
||||||
|
|
||||||
export const customIdValidator = z.string().min(1).max(100);
|
export const customIdValidator = z.string().min(1).max(100);
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ export const minMaxValidator = z.number().int().min(0).max(25);
|
|||||||
|
|
||||||
export const optionsValidator = z.object({}).array().nonempty();
|
export const optionsValidator = z.object({}).array().nonempty();
|
||||||
|
|
||||||
export function validateRequiredSelectMenuParameters(options: SelectMenuOption[], customId?: string) {
|
export function validateRequiredSelectMenuParameters(options: SelectMenuOptionBuilder[], customId?: string) {
|
||||||
customIdValidator.parse(customId);
|
customIdValidator.parse(customId);
|
||||||
optionsValidator.parse(options);
|
optionsValidator.parse(options);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,17 +4,16 @@ import type {
|
|||||||
APIActionRowComponentTypes,
|
APIActionRowComponentTypes,
|
||||||
APIBaseComponent,
|
APIBaseComponent,
|
||||||
APIMessageActionRowComponent,
|
APIMessageActionRowComponent,
|
||||||
APIModalActionRowComponent,
|
|
||||||
APIMessageComponent,
|
APIMessageComponent,
|
||||||
ComponentType,
|
APIModalActionRowComponent,
|
||||||
APIModalComponent,
|
APIModalComponent,
|
||||||
|
ComponentType,
|
||||||
} from 'discord-api-types/v9';
|
} from 'discord-api-types/v9';
|
||||||
import type { Equatable } from '../util/equatable';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a discord component
|
* Represents a discord component
|
||||||
*/
|
*/
|
||||||
export abstract class Component<
|
export abstract class ComponentBuilder<
|
||||||
DataType extends Partial<APIBaseComponent<ComponentType>> & {
|
DataType extends Partial<APIBaseComponent<ComponentType>> & {
|
||||||
type: ComponentType;
|
type: ComponentType;
|
||||||
} = APIBaseComponent<ComponentType>,
|
} = APIBaseComponent<ComponentType>,
|
||||||
@@ -23,11 +22,6 @@ export abstract class Component<
|
|||||||
| APIModalComponent
|
| APIModalComponent
|
||||||
| APIMessageComponent
|
| APIMessageComponent
|
||||||
| APIActionRowComponent<APIModalActionRowComponent | APIMessageActionRowComponent>
|
| APIActionRowComponent<APIModalActionRowComponent | APIMessageActionRowComponent>
|
||||||
>,
|
|
||||||
Equatable<
|
|
||||||
| Component
|
|
||||||
| APIActionRowComponentTypes
|
|
||||||
| APIActionRowComponent<APIModalActionRowComponent | APIMessageActionRowComponent>
|
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@@ -39,21 +33,7 @@ export abstract class Component<
|
|||||||
| APIActionRowComponentTypes
|
| APIActionRowComponentTypes
|
||||||
| APIActionRowComponent<APIModalActionRowComponent | APIMessageActionRowComponent>;
|
| APIActionRowComponent<APIModalActionRowComponent | APIMessageActionRowComponent>;
|
||||||
|
|
||||||
public abstract equals(
|
|
||||||
other:
|
|
||||||
| Component
|
|
||||||
| APIActionRowComponentTypes
|
|
||||||
| APIActionRowComponent<APIModalActionRowComponent | APIMessageActionRowComponent>,
|
|
||||||
): boolean;
|
|
||||||
|
|
||||||
public constructor(data: DataType) {
|
public constructor(data: DataType) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The type of this component
|
|
||||||
*/
|
|
||||||
public get type(): DataType['type'] {
|
|
||||||
return this.data.type;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +1,41 @@
|
|||||||
import { APIBaseComponent, APIMessageComponent, APIModalComponent, ComponentType } from 'discord-api-types/v9';
|
import { APIMessageComponent, APIModalComponent, ComponentType } from 'discord-api-types/v9';
|
||||||
import { ActionRow, ButtonComponent, Component, SelectMenuComponent, TextInputComponent } from '../index';
|
import { ActionRowBuilder, ButtonBuilder, ComponentBuilder, SelectMenuBuilder, TextInputBuilder } from '../index';
|
||||||
import type { MessageComponent, ModalActionRowComponent } from './ActionRow';
|
import type { MessageComponentBuilder, ModalComponentBuilder } from './ActionRow';
|
||||||
|
|
||||||
export interface MappedComponentTypes {
|
export interface MappedComponentTypes {
|
||||||
[ComponentType.ActionRow]: ActionRow;
|
[ComponentType.ActionRow]: ActionRowBuilder;
|
||||||
[ComponentType.Button]: ButtonComponent;
|
[ComponentType.Button]: ButtonBuilder;
|
||||||
[ComponentType.SelectMenu]: SelectMenuComponent;
|
[ComponentType.SelectMenu]: SelectMenuBuilder;
|
||||||
[ComponentType.TextInput]: TextInputComponent;
|
[ComponentType.TextInput]: TextInputBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory for creating components from API data
|
* Factory for creating components from API data
|
||||||
* @param data The api data to transform to a component class
|
* @param data The api data to transform to a component class
|
||||||
*/
|
*/
|
||||||
export function createComponent<T extends keyof MappedComponentTypes>(
|
export function createComponentBuilder<T extends keyof MappedComponentTypes>(
|
||||||
data: (APIMessageComponent | APIModalComponent) & { type: T },
|
data: (APIMessageComponent | APIModalComponent) & { type: T },
|
||||||
): MappedComponentTypes[T];
|
): MappedComponentTypes[T];
|
||||||
export function createComponent<C extends MessageComponent | ModalActionRowComponent>(data: C): C;
|
export function createComponentBuilder<C extends MessageComponentBuilder | ModalComponentBuilder>(data: C): C;
|
||||||
export function createComponent(data: APIModalComponent | APIMessageComponent | Component): Component {
|
export function createComponentBuilder(
|
||||||
if (data instanceof Component) {
|
data: APIMessageComponent | APIModalComponent | MessageComponentBuilder,
|
||||||
|
): ComponentBuilder {
|
||||||
|
if (data instanceof ComponentBuilder) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
case ComponentType.ActionRow:
|
case ComponentType.ActionRow:
|
||||||
return new ActionRow(data);
|
return new ActionRowBuilder(data);
|
||||||
case ComponentType.Button:
|
case ComponentType.Button:
|
||||||
return new ButtonComponent(data);
|
return new ButtonBuilder(data);
|
||||||
case ComponentType.SelectMenu:
|
case ComponentType.SelectMenu:
|
||||||
return new SelectMenuComponent(data);
|
return new SelectMenuBuilder(data);
|
||||||
case ComponentType.TextInput:
|
case ComponentType.TextInput:
|
||||||
return new TextInputComponent(data);
|
return new TextInputBuilder(data);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Cannot serialize component type: ${(data as APIBaseComponent<ComponentType>).type}`);
|
// @ts-expect-error
|
||||||
|
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||||
|
throw new Error(`Cannot properly serialize component type: ${data.type}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
import type { ButtonStyle, APIMessageComponentEmoji, APIButtonComponent } from 'discord-api-types/v9';
|
import type {
|
||||||
|
ButtonStyle,
|
||||||
|
APIMessageComponentEmoji,
|
||||||
|
APIButtonComponent,
|
||||||
|
APIButtonComponentWithCustomId,
|
||||||
|
APIButtonComponentWithURL,
|
||||||
|
} from 'discord-api-types/v9';
|
||||||
import {
|
import {
|
||||||
buttonLabelValidator,
|
buttonLabelValidator,
|
||||||
buttonStyleValidator,
|
buttonStyleValidator,
|
||||||
@@ -8,12 +14,12 @@ import {
|
|||||||
urlValidator,
|
urlValidator,
|
||||||
validateRequiredButtonParameters,
|
validateRequiredButtonParameters,
|
||||||
} from '../Assertions';
|
} from '../Assertions';
|
||||||
import { UnsafeButtonComponent } from './UnsafeButton';
|
import { UnsafeButtonBuilder } from './UnsafeButton';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a validated button component
|
* Represents a validated button component
|
||||||
*/
|
*/
|
||||||
export class ButtonComponent extends UnsafeButtonComponent {
|
export class ButtonBuilder extends UnsafeButtonBuilder {
|
||||||
public override setStyle(style: ButtonStyle) {
|
public override setStyle(style: ButtonStyle) {
|
||||||
return super.setStyle(buttonStyleValidator.parse(style));
|
return super.setStyle(buttonStyleValidator.parse(style));
|
||||||
}
|
}
|
||||||
@@ -39,7 +45,13 @@ export class ButtonComponent extends UnsafeButtonComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override toJSON(): APIButtonComponent {
|
public override toJSON(): APIButtonComponent {
|
||||||
validateRequiredButtonParameters(this.style, this.label, this.emoji, this.customId, this.url);
|
validateRequiredButtonParameters(
|
||||||
|
this.data.style,
|
||||||
|
this.data.label,
|
||||||
|
this.data.emoji,
|
||||||
|
(this.data as APIButtonComponentWithCustomId).custom_id,
|
||||||
|
(this.data as APIButtonComponentWithURL).url,
|
||||||
|
);
|
||||||
return super.toJSON();
|
return super.toJSON();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,59 +6,18 @@ import {
|
|||||||
type APIButtonComponentWithURL,
|
type APIButtonComponentWithURL,
|
||||||
type APIButtonComponentWithCustomId,
|
type APIButtonComponentWithCustomId,
|
||||||
} from 'discord-api-types/v9';
|
} from 'discord-api-types/v9';
|
||||||
import { Component } from '../Component';
|
import { ComponentBuilder } from '../Component';
|
||||||
import isEqual from 'fast-deep-equal';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a non-validated button component
|
* Represents a non-validated button component
|
||||||
*/
|
*/
|
||||||
export class UnsafeButtonComponent extends Component<Partial<APIButtonComponent> & { type: ComponentType.Button }> {
|
export class UnsafeButtonBuilder extends ComponentBuilder<
|
||||||
|
Partial<APIButtonComponent> & { type: ComponentType.Button }
|
||||||
|
> {
|
||||||
public constructor(data?: Partial<APIButtonComponent>) {
|
public constructor(data?: Partial<APIButtonComponent>) {
|
||||||
super({ type: ComponentType.Button, ...data });
|
super({ type: ComponentType.Button, ...data });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The style of this button
|
|
||||||
*/
|
|
||||||
public get style() {
|
|
||||||
return this.data.style;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The label of this button
|
|
||||||
*/
|
|
||||||
public get label() {
|
|
||||||
return this.data.label;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The emoji used in this button
|
|
||||||
*/
|
|
||||||
public get emoji() {
|
|
||||||
return this.data.emoji;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether this button is disabled
|
|
||||||
*/
|
|
||||||
public get disabled() {
|
|
||||||
return this.data.disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The custom id of this button (only defined on non-link buttons)
|
|
||||||
*/
|
|
||||||
public get customId(): string | undefined {
|
|
||||||
return (this.data as APIButtonComponentWithCustomId).custom_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The URL of this button (only defined on link buttons)
|
|
||||||
*/
|
|
||||||
public get url(): string | undefined {
|
|
||||||
return (this.data as APIButtonComponentWithURL).url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the style of this button
|
* Sets the style of this button
|
||||||
* @param style The style of the button
|
* @param style The style of the button
|
||||||
@@ -119,11 +78,4 @@ export class UnsafeButtonComponent extends Component<Partial<APIButtonComponent>
|
|||||||
...this.data,
|
...this.data,
|
||||||
} as APIButtonComponent;
|
} as APIButtonComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public equals(other: APIButtonComponent | UnsafeButtonComponent) {
|
|
||||||
if (other instanceof UnsafeButtonComponent) {
|
|
||||||
return isEqual(other.data, this.data);
|
|
||||||
}
|
|
||||||
return isEqual(other, this.data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ import {
|
|||||||
placeholderValidator,
|
placeholderValidator,
|
||||||
validateRequiredSelectMenuParameters,
|
validateRequiredSelectMenuParameters,
|
||||||
} from '../Assertions';
|
} from '../Assertions';
|
||||||
import { UnsafeSelectMenuComponent } from './UnsafeSelectMenu';
|
import { UnsafeSelectMenuBuilder } from './UnsafeSelectMenu';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a validated select menu component
|
* Represents a validated select menu component
|
||||||
*/
|
*/
|
||||||
export class SelectMenuComponent extends UnsafeSelectMenuComponent {
|
export class SelectMenuBuilder extends UnsafeSelectMenuBuilder {
|
||||||
public override setPlaceholder(placeholder: string) {
|
public override setPlaceholder(placeholder: string) {
|
||||||
return super.setPlaceholder(placeholderValidator.parse(placeholder));
|
return super.setPlaceholder(placeholderValidator.parse(placeholder));
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,7 @@ export class SelectMenuComponent extends UnsafeSelectMenuComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override toJSON(): APISelectMenuComponent {
|
public override toJSON(): APISelectMenuComponent {
|
||||||
validateRequiredSelectMenuParameters(this.options, this.customId);
|
validateRequiredSelectMenuParameters(this.options, this.data.custom_id);
|
||||||
return super.toJSON();
|
return super.toJSON();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ import {
|
|||||||
labelValueValidator,
|
labelValueValidator,
|
||||||
validateRequiredSelectMenuOptionParameters,
|
validateRequiredSelectMenuOptionParameters,
|
||||||
} from '../Assertions';
|
} from '../Assertions';
|
||||||
import { UnsafeSelectMenuOption } from './UnsafeSelectMenuOption';
|
import { UnsafeSelectMenuOptionBuilder } from './UnsafeSelectMenuOption';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a validated option within a select menu component
|
* Represents a validated option within a select menu component
|
||||||
*/
|
*/
|
||||||
export class SelectMenuOption extends UnsafeSelectMenuOption {
|
export class SelectMenuOptionBuilder extends UnsafeSelectMenuOptionBuilder {
|
||||||
public override setDescription(description: string) {
|
public override setDescription(description: string) {
|
||||||
return super.setDescription(labelValueValidator.parse(description));
|
return super.setDescription(labelValueValidator.parse(description));
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ export class SelectMenuOption extends UnsafeSelectMenuOption {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override toJSON(): APISelectMenuOption {
|
public override toJSON(): APISelectMenuOption {
|
||||||
validateRequiredSelectMenuOptionParameters(this.label, this.value);
|
validateRequiredSelectMenuOptionParameters(this.data.label, this.data.value);
|
||||||
return super.toJSON();
|
return super.toJSON();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,58 +1,22 @@
|
|||||||
import { APISelectMenuOption, ComponentType, type APISelectMenuComponent } from 'discord-api-types/v9';
|
import { APISelectMenuOption, ComponentType, type APISelectMenuComponent } from 'discord-api-types/v9';
|
||||||
import { Component } from '../Component';
|
import { ComponentBuilder } from '../Component';
|
||||||
import { UnsafeSelectMenuOption } from './UnsafeSelectMenuOption';
|
import { UnsafeSelectMenuOptionBuilder } from './UnsafeSelectMenuOption';
|
||||||
import isEqual from 'fast-deep-equal';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a non-validated select menu component
|
* Represents a non-validated select menu component
|
||||||
*/
|
*/
|
||||||
export class UnsafeSelectMenuComponent extends Component<
|
export class UnsafeSelectMenuBuilder extends ComponentBuilder<
|
||||||
Partial<Omit<APISelectMenuComponent, 'options'>> & { type: ComponentType.SelectMenu }
|
Partial<Omit<APISelectMenuComponent, 'options'>> & { type: ComponentType.SelectMenu }
|
||||||
> {
|
> {
|
||||||
/**
|
/**
|
||||||
* The options within this select menu
|
* The options within this select menu
|
||||||
*/
|
*/
|
||||||
public readonly options: UnsafeSelectMenuOption[];
|
protected readonly options: UnsafeSelectMenuOptionBuilder[];
|
||||||
|
|
||||||
public constructor(data?: Partial<APISelectMenuComponent>) {
|
public constructor(data?: Partial<APISelectMenuComponent>) {
|
||||||
const { options, ...initData } = data ?? {};
|
const { options, ...initData } = data ?? {};
|
||||||
super({ type: ComponentType.SelectMenu, ...initData });
|
super({ type: ComponentType.SelectMenu, ...initData });
|
||||||
this.options = options?.map((o) => new UnsafeSelectMenuOption(o)) ?? [];
|
this.options = options?.map((o) => new UnsafeSelectMenuOptionBuilder(o)) ?? [];
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The placeholder for this select menu
|
|
||||||
*/
|
|
||||||
public get placeholder() {
|
|
||||||
return this.data.placeholder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The maximum amount of options that can be selected
|
|
||||||
*/
|
|
||||||
public get maxValues() {
|
|
||||||
return this.data.max_values;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The minimum amount of options that must be selected
|
|
||||||
*/
|
|
||||||
public get minValues() {
|
|
||||||
return this.data.min_values;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The custom id of this select menu
|
|
||||||
*/
|
|
||||||
public get customId() {
|
|
||||||
return this.data.custom_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether this select menu is disabled
|
|
||||||
*/
|
|
||||||
public get disabled() {
|
|
||||||
return this.data.disabled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -105,10 +69,10 @@ export class UnsafeSelectMenuComponent extends Component<
|
|||||||
* @param options The options to add to this select menu
|
* @param options The options to add to this select menu
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public addOptions(...options: (UnsafeSelectMenuOption | APISelectMenuOption)[]) {
|
public addOptions(...options: (UnsafeSelectMenuOptionBuilder | APISelectMenuOption)[]) {
|
||||||
this.options.push(
|
this.options.push(
|
||||||
...options.map((option) =>
|
...options.map((option) =>
|
||||||
option instanceof UnsafeSelectMenuOption ? option : new UnsafeSelectMenuOption(option),
|
option instanceof UnsafeSelectMenuOptionBuilder ? option : new UnsafeSelectMenuOptionBuilder(option),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return this;
|
return this;
|
||||||
@@ -118,12 +82,12 @@ export class UnsafeSelectMenuComponent extends Component<
|
|||||||
* Sets the options on this select menu
|
* Sets the options on this select menu
|
||||||
* @param options The options to set on this select menu
|
* @param options The options to set on this select menu
|
||||||
*/
|
*/
|
||||||
public setOptions(...options: (UnsafeSelectMenuOption | APISelectMenuOption)[]) {
|
public setOptions(...options: (UnsafeSelectMenuOptionBuilder | APISelectMenuOption)[]) {
|
||||||
this.options.splice(
|
this.options.splice(
|
||||||
0,
|
0,
|
||||||
this.options.length,
|
this.options.length,
|
||||||
...options.map((option) =>
|
...options.map((option) =>
|
||||||
option instanceof UnsafeSelectMenuOption ? option : new UnsafeSelectMenuOption(option),
|
option instanceof UnsafeSelectMenuOptionBuilder ? option : new UnsafeSelectMenuOptionBuilder(option),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return this;
|
return this;
|
||||||
@@ -136,14 +100,4 @@ export class UnsafeSelectMenuComponent extends Component<
|
|||||||
options: this.options.map((o) => o.toJSON()),
|
options: this.options.map((o) => o.toJSON()),
|
||||||
} as APISelectMenuComponent;
|
} as APISelectMenuComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public equals(other: APISelectMenuComponent | UnsafeSelectMenuComponent): boolean {
|
|
||||||
if (other instanceof UnsafeSelectMenuComponent) {
|
|
||||||
return isEqual(other.data, this.data) && isEqual(other.options, this.options);
|
|
||||||
}
|
|
||||||
return isEqual(other, {
|
|
||||||
...this.data,
|
|
||||||
options: this.options.map((o) => o.toJSON()),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,43 +3,8 @@ import type { APIMessageComponentEmoji, APISelectMenuOption } from 'discord-api-
|
|||||||
/**
|
/**
|
||||||
* Represents a non-validated option within a select menu component
|
* Represents a non-validated option within a select menu component
|
||||||
*/
|
*/
|
||||||
export class UnsafeSelectMenuOption {
|
export class UnsafeSelectMenuOptionBuilder {
|
||||||
public constructor(protected data: Partial<APISelectMenuOption> = {}) {}
|
public constructor(public data: Partial<APISelectMenuOption> = {}) {}
|
||||||
|
|
||||||
/**
|
|
||||||
* The label for this option
|
|
||||||
*/
|
|
||||||
public get label() {
|
|
||||||
return this.data.label;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The value for this option
|
|
||||||
*/
|
|
||||||
public get value() {
|
|
||||||
return this.data.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The description for this option
|
|
||||||
*/
|
|
||||||
public get description() {
|
|
||||||
return this.data.description;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The emoji for this option
|
|
||||||
*/
|
|
||||||
public get emoji() {
|
|
||||||
return this.data.emoji;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether this option is selected by default
|
|
||||||
*/
|
|
||||||
public get default() {
|
|
||||||
return this.data.default;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the label of this option
|
* Sets the label of this option
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import {
|
|||||||
valueValidator,
|
valueValidator,
|
||||||
validateRequiredParameters,
|
validateRequiredParameters,
|
||||||
} from './Assertions';
|
} from './Assertions';
|
||||||
import { UnsafeTextInputComponent } from './UnsafeTextInput';
|
import { UnsafeTextInputBuilder } from './UnsafeTextInput';
|
||||||
|
|
||||||
export class TextInputComponent extends UnsafeTextInputComponent {
|
export class TextInputBuilder extends UnsafeTextInputBuilder {
|
||||||
public override setMinLength(minLength: number) {
|
public override setMinLength(minLength: number) {
|
||||||
return super.setMinLength(minLengthValidator.parse(minLength));
|
return super.setMinLength(minLengthValidator.parse(minLength));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,73 +1,17 @@
|
|||||||
import { ComponentType, type TextInputStyle, type APITextInputComponent } from 'discord-api-types/v9';
|
import { ComponentType, type TextInputStyle, type APITextInputComponent } from 'discord-api-types/v9';
|
||||||
import { Component } from '../../index';
|
import { ComponentBuilder } from '../../index';
|
||||||
import isEqual from 'fast-deep-equal';
|
import isEqual from 'fast-deep-equal';
|
||||||
|
|
||||||
export class UnsafeTextInputComponent extends Component<
|
export class UnsafeTextInputBuilder extends ComponentBuilder<
|
||||||
Partial<APITextInputComponent> & { type: ComponentType.TextInput }
|
Partial<APITextInputComponent> & { type: ComponentType.TextInput }
|
||||||
> {
|
> {
|
||||||
public constructor(data?: APITextInputComponent & { type?: ComponentType.TextInput }) {
|
public constructor(data?: APITextInputComponent & { type?: ComponentType.TextInput }) {
|
||||||
super({ type: ComponentType.TextInput, ...data });
|
super({ type: ComponentType.TextInput, ...data });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The style of this text input
|
|
||||||
*/
|
|
||||||
public get style() {
|
|
||||||
return this.data.style;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The custom id of this text input
|
|
||||||
*/
|
|
||||||
public get customId() {
|
|
||||||
return this.data.custom_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The label for this text input
|
|
||||||
*/
|
|
||||||
public get label() {
|
|
||||||
return this.data.label;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The placeholder text for this text input
|
|
||||||
*/
|
|
||||||
public get placeholder() {
|
|
||||||
return this.data.placeholder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default value for this text input
|
|
||||||
*/
|
|
||||||
public get value() {
|
|
||||||
return this.data.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The minimum length of this text input
|
|
||||||
*/
|
|
||||||
public get minLength() {
|
|
||||||
return this.data.min_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The maximum length of this text input
|
|
||||||
*/
|
|
||||||
public get maxLength() {
|
|
||||||
return this.data.max_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether this text input is required
|
|
||||||
*/
|
|
||||||
public get required() {
|
|
||||||
return this.data.required;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the custom id for this text input
|
* Sets the custom id for this text input
|
||||||
* @param customId The custom id of this text input
|
* @param customId The custom id of this text inputå
|
||||||
*/
|
*/
|
||||||
public setCustomId(customId: string) {
|
public setCustomId(customId: string) {
|
||||||
this.data.custom_id = customId;
|
this.data.custom_id = customId;
|
||||||
@@ -144,8 +88,8 @@ export class UnsafeTextInputComponent extends Component<
|
|||||||
} as APITextInputComponent;
|
} as APITextInputComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public equals(other: UnsafeTextInputComponent | APITextInputComponent): boolean {
|
public equals(other: UnsafeTextInputBuilder | APITextInputComponent): boolean {
|
||||||
if (other instanceof UnsafeTextInputComponent) {
|
if (other instanceof UnsafeTextInputBuilder) {
|
||||||
return isEqual(other.data, this.data);
|
return isEqual(other.data, this.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,3 +37,5 @@ export * as ContextMenuCommandAssertions from './interactions/contextMenuCommand
|
|||||||
export * from './interactions/contextMenuCommands/ContextMenuCommandBuilder';
|
export * from './interactions/contextMenuCommands/ContextMenuCommandBuilder';
|
||||||
|
|
||||||
export * from './util/jsonEncodable';
|
export * from './util/jsonEncodable';
|
||||||
|
export * from './util/equatable';
|
||||||
|
export * from './util/componentUtil';
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { ActionRow, type ModalActionRowComponent } from '../..';
|
import { ActionRowBuilder, type ModalActionRowComponentBuilder } from '../..';
|
||||||
import { customIdValidator } from '../../components/Assertions';
|
import { customIdValidator } from '../../components/Assertions';
|
||||||
|
|
||||||
export const titleValidator = z.string().min(1).max(45);
|
export const titleValidator = z.string().min(1).max(45);
|
||||||
export const componentsValidator = z.array(z.instanceof(ActionRow)).min(1);
|
export const componentsValidator = z.array(z.instanceof(ActionRowBuilder)).min(1);
|
||||||
|
|
||||||
export function validateRequiredParameters(
|
export function validateRequiredParameters(
|
||||||
customId?: string,
|
customId?: string,
|
||||||
title?: string,
|
title?: string,
|
||||||
components?: ActionRow<ModalActionRowComponent>[],
|
components?: ActionRowBuilder<ModalActionRowComponentBuilder>[],
|
||||||
) {
|
) {
|
||||||
customIdValidator.parse(customId);
|
customIdValidator.parse(customId);
|
||||||
titleValidator.parse(title);
|
titleValidator.parse(title);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import type { APIModalInteractionResponseCallbackData } from 'discord-api-types/v9';
|
import type { APIModalInteractionResponseCallbackData } from 'discord-api-types/v9';
|
||||||
import { customIdValidator } from '../../components/Assertions';
|
import { customIdValidator } from '../../components/Assertions';
|
||||||
import { titleValidator, validateRequiredParameters } from './Assertions';
|
import { titleValidator, validateRequiredParameters } from './Assertions';
|
||||||
import { UnsafeModal } from './UnsafeModal';
|
import { UnsafeModalBuilder } from './UnsafeModal';
|
||||||
|
|
||||||
export class Modal extends UnsafeModal {
|
export class ModalBuilder extends UnsafeModalBuilder {
|
||||||
public override setCustomId(customId: string): this {
|
public override setCustomId(customId: string): this {
|
||||||
return super.setCustomId(customIdValidator.parse(customId));
|
return super.setCustomId(customIdValidator.parse(customId));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,29 +3,16 @@ import type {
|
|||||||
APIModalActionRowComponent,
|
APIModalActionRowComponent,
|
||||||
APIModalInteractionResponseCallbackData,
|
APIModalInteractionResponseCallbackData,
|
||||||
} from 'discord-api-types/v9';
|
} from 'discord-api-types/v9';
|
||||||
import { ActionRow, createComponent, JSONEncodable, ModalActionRowComponent } from '../../index';
|
import { ActionRowBuilder, createComponentBuilder, JSONEncodable, ModalActionRowComponentBuilder } from '../../index';
|
||||||
|
|
||||||
export class UnsafeModal implements JSONEncodable<APIModalInteractionResponseCallbackData> {
|
export class UnsafeModalBuilder implements JSONEncodable<APIModalInteractionResponseCallbackData> {
|
||||||
protected readonly data: Partial<Omit<APIModalInteractionResponseCallbackData, 'components'>>;
|
protected readonly data: Partial<Omit<APIModalInteractionResponseCallbackData, 'components'>>;
|
||||||
public readonly components: ActionRow<ModalActionRowComponent>[] = [];
|
public readonly components: ActionRowBuilder<ModalActionRowComponentBuilder>[] = [];
|
||||||
|
|
||||||
public constructor({ components, ...data }: Partial<APIModalInteractionResponseCallbackData> = {}) {
|
public constructor({ components, ...data }: Partial<APIModalInteractionResponseCallbackData> = {}) {
|
||||||
this.data = { ...data };
|
this.data = { ...data };
|
||||||
this.components = (components?.map((c) => createComponent(c)) ?? []) as ActionRow<ModalActionRowComponent>[];
|
this.components = (components?.map((c) => createComponentBuilder(c)) ??
|
||||||
}
|
[]) as ActionRowBuilder<ModalActionRowComponentBuilder>[];
|
||||||
|
|
||||||
/**
|
|
||||||
* The custom id of this modal
|
|
||||||
*/
|
|
||||||
public get customId() {
|
|
||||||
return this.data.custom_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The title of this modal
|
|
||||||
*/
|
|
||||||
public get title() {
|
|
||||||
return this.data.title;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,11 +38,16 @@ export class UnsafeModal implements JSONEncodable<APIModalInteractionResponseCal
|
|||||||
* @param components The components to add to this modal
|
* @param components The components to add to this modal
|
||||||
*/
|
*/
|
||||||
public addComponents(
|
public addComponents(
|
||||||
...components: (ActionRow<ModalActionRowComponent> | APIActionRowComponent<APIModalActionRowComponent>)[]
|
...components: (
|
||||||
|
| ActionRowBuilder<ModalActionRowComponentBuilder>
|
||||||
|
| APIActionRowComponent<APIModalActionRowComponent>
|
||||||
|
)[]
|
||||||
) {
|
) {
|
||||||
this.components.push(
|
this.components.push(
|
||||||
...components.map((component) =>
|
...components.map((component) =>
|
||||||
component instanceof ActionRow ? component : new ActionRow<ModalActionRowComponent>(component),
|
component instanceof ActionRowBuilder
|
||||||
|
? component
|
||||||
|
: new ActionRowBuilder<ModalActionRowComponentBuilder>(component),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return this;
|
return this;
|
||||||
@@ -65,7 +57,7 @@ export class UnsafeModal implements JSONEncodable<APIModalInteractionResponseCal
|
|||||||
* Sets the components in this modal
|
* Sets the components in this modal
|
||||||
* @param components The components to set this modal to
|
* @param components The components to set this modal to
|
||||||
*/
|
*/
|
||||||
public setComponents(...components: ActionRow<ModalActionRowComponent>[]) {
|
public setComponents(...components: ActionRowBuilder<ModalActionRowComponentBuilder>[]) {
|
||||||
this.components.splice(0, this.components.length, ...components);
|
this.components.splice(0, this.components.length, ...components);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,15 +10,15 @@ import {
|
|||||||
urlPredicate,
|
urlPredicate,
|
||||||
validateFieldLength,
|
validateFieldLength,
|
||||||
} from './Assertions';
|
} from './Assertions';
|
||||||
import { EmbedAuthorOptions, EmbedFooterOptions, RGBTuple, UnsafeEmbed } from './UnsafeEmbed';
|
import { EmbedAuthorOptions, EmbedFooterOptions, RGBTuple, UnsafeEmbedBuilder } from './UnsafeEmbed';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a validated embed in a message (image/video preview, rich embed, etc.)
|
* Represents a validated embed in a message (image/video preview, rich embed, etc.)
|
||||||
*/
|
*/
|
||||||
export class Embed extends UnsafeEmbed {
|
export class EmbedBuilder extends UnsafeEmbedBuilder {
|
||||||
public override addFields(...fields: APIEmbedField[]): this {
|
public override addFields(...fields: APIEmbedField[]): this {
|
||||||
// Ensure adding these fields won't exceed the 25 field limit
|
// Ensure adding these fields won't exceed the 25 field limit
|
||||||
validateFieldLength(fields.length, this.fields);
|
validateFieldLength(fields.length, this.data.fields);
|
||||||
|
|
||||||
// Data assertions
|
// Data assertions
|
||||||
return super.addFields(...embedFieldsArrayPredicate.parse(fields));
|
return super.addFields(...embedFieldsArrayPredicate.parse(fields));
|
||||||
@@ -26,7 +26,7 @@ export class Embed extends UnsafeEmbed {
|
|||||||
|
|
||||||
public override spliceFields(index: number, deleteCount: number, ...fields: APIEmbedField[]): this {
|
public override spliceFields(index: number, deleteCount: number, ...fields: APIEmbedField[]): this {
|
||||||
// Ensure adding these fields won't exceed the 25 field limit
|
// Ensure adding these fields won't exceed the 25 field limit
|
||||||
validateFieldLength(fields.length - deleteCount, this.fields);
|
validateFieldLength(fields.length - deleteCount, this.data.fields);
|
||||||
|
|
||||||
// Data assertions
|
// Data assertions
|
||||||
return super.spliceFields(index, deleteCount, ...embedFieldsArrayPredicate.parse(fields));
|
return super.spliceFields(index, deleteCount, ...embedFieldsArrayPredicate.parse(fields));
|
||||||
|
|||||||
@@ -1,13 +1,4 @@
|
|||||||
import type {
|
import type { APIEmbed, APIEmbedAuthor, APIEmbedField, APIEmbedFooter, APIEmbedImage } from 'discord-api-types/v9';
|
||||||
APIEmbed,
|
|
||||||
APIEmbedAuthor,
|
|
||||||
APIEmbedField,
|
|
||||||
APIEmbedFooter,
|
|
||||||
APIEmbedImage,
|
|
||||||
APIEmbedVideo,
|
|
||||||
} from 'discord-api-types/v9';
|
|
||||||
import type { Equatable } from '../../util/equatable';
|
|
||||||
import isEqual from 'fast-deep-equal';
|
|
||||||
|
|
||||||
export type RGBTuple = [red: number, green: number, blue: number];
|
export type RGBTuple = [red: number, green: number, blue: number];
|
||||||
|
|
||||||
@@ -40,7 +31,7 @@ export interface EmbedImageData extends Omit<APIEmbedImage, 'proxy_url'> {
|
|||||||
/**
|
/**
|
||||||
* Represents a non-validated embed in a message (image/video preview, rich embed, etc.)
|
* Represents a non-validated embed in a message (image/video preview, rich embed, etc.)
|
||||||
*/
|
*/
|
||||||
export class UnsafeEmbed implements Equatable<APIEmbed | UnsafeEmbed> {
|
export class UnsafeEmbedBuilder {
|
||||||
public readonly data: APIEmbed;
|
public readonly data: APIEmbed;
|
||||||
|
|
||||||
public constructor(data: APIEmbed = {}) {
|
public constructor(data: APIEmbed = {}) {
|
||||||
@@ -48,133 +39,6 @@ export class UnsafeEmbed implements Equatable<APIEmbed | UnsafeEmbed> {
|
|||||||
if (data.timestamp) this.data.timestamp = new Date(data.timestamp).toISOString();
|
if (data.timestamp) this.data.timestamp = new Date(data.timestamp).toISOString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* An array of fields of this embed
|
|
||||||
*/
|
|
||||||
public get fields() {
|
|
||||||
return this.data.fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The embed title
|
|
||||||
*/
|
|
||||||
public get title() {
|
|
||||||
return this.data.title;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The embed description
|
|
||||||
*/
|
|
||||||
public get description() {
|
|
||||||
return this.data.description;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The embed URL
|
|
||||||
*/
|
|
||||||
public get url() {
|
|
||||||
return this.data.url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The embed color
|
|
||||||
*/
|
|
||||||
public get color() {
|
|
||||||
return this.data.color;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The timestamp of the embed in an ISO 8601 format
|
|
||||||
*/
|
|
||||||
public get timestamp() {
|
|
||||||
return this.data.timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The embed thumbnail data
|
|
||||||
*/
|
|
||||||
public get thumbnail(): EmbedImageData | undefined {
|
|
||||||
if (!this.data.thumbnail) return undefined;
|
|
||||||
return {
|
|
||||||
url: this.data.thumbnail.url,
|
|
||||||
proxyURL: this.data.thumbnail.proxy_url,
|
|
||||||
height: this.data.thumbnail.height,
|
|
||||||
width: this.data.thumbnail.width,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The embed image data
|
|
||||||
*/
|
|
||||||
public get image(): EmbedImageData | undefined {
|
|
||||||
if (!this.data.image) return undefined;
|
|
||||||
return {
|
|
||||||
url: this.data.image.url,
|
|
||||||
proxyURL: this.data.image.proxy_url,
|
|
||||||
height: this.data.image.height,
|
|
||||||
width: this.data.image.width,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Received video data
|
|
||||||
*/
|
|
||||||
public get video(): APIEmbedVideo | undefined {
|
|
||||||
return this.data.video;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The embed author data
|
|
||||||
*/
|
|
||||||
public get author(): EmbedAuthorData | undefined {
|
|
||||||
if (!this.data.author) return undefined;
|
|
||||||
return {
|
|
||||||
name: this.data.author.name,
|
|
||||||
url: this.data.author.url,
|
|
||||||
iconURL: this.data.author.icon_url,
|
|
||||||
proxyIconURL: this.data.author.proxy_icon_url,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Received data about the embed provider
|
|
||||||
*/
|
|
||||||
public get provider() {
|
|
||||||
return this.data.provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The embed footer data
|
|
||||||
*/
|
|
||||||
public get footer(): EmbedFooterData | undefined {
|
|
||||||
if (!this.data.footer) return undefined;
|
|
||||||
return {
|
|
||||||
text: this.data.footer.text,
|
|
||||||
iconURL: this.data.footer.icon_url,
|
|
||||||
proxyIconURL: this.data.footer.proxy_icon_url,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The accumulated length for the embed title, description, fields, footer text, and author name
|
|
||||||
*/
|
|
||||||
public get length(): number {
|
|
||||||
return (
|
|
||||||
(this.data.title?.length ?? 0) +
|
|
||||||
(this.data.description?.length ?? 0) +
|
|
||||||
(this.data.fields?.reduce((prev, curr) => prev + curr.name.length + curr.value.length, 0) ?? 0) +
|
|
||||||
(this.data.footer?.text.length ?? 0) +
|
|
||||||
(this.data.author?.name.length ?? 0)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The hex color of the current color of the embed
|
|
||||||
*/
|
|
||||||
public get hexColor() {
|
|
||||||
return typeof this.data.color === 'number' ? `#${this.data.color.toString(16).padStart(6, '0')}` : this.data.color;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds fields to the embed (max 25)
|
* Adds fields to the embed (max 25)
|
||||||
*
|
*
|
||||||
@@ -204,7 +68,7 @@ export class UnsafeEmbed implements Equatable<APIEmbed | UnsafeEmbed> {
|
|||||||
* @param fields The fields to set
|
* @param fields The fields to set
|
||||||
*/
|
*/
|
||||||
public setFields(...fields: APIEmbedField[]) {
|
public setFields(...fields: APIEmbedField[]) {
|
||||||
this.spliceFields(0, this.fields?.length ?? 0, ...fields);
|
this.spliceFields(0, this.data.fields?.length ?? 0, ...fields);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,11 +183,4 @@ export class UnsafeEmbed implements Equatable<APIEmbed | UnsafeEmbed> {
|
|||||||
public toJSON(): APIEmbed {
|
public toJSON(): APIEmbed {
|
||||||
return { ...this.data };
|
return { ...this.data };
|
||||||
}
|
}
|
||||||
|
|
||||||
public equals(other: UnsafeEmbed | APIEmbed) {
|
|
||||||
const { image: thisImage, thumbnail: thisThumbnail, ...thisData } = this.data;
|
|
||||||
const data = other instanceof UnsafeEmbed ? other.data : other;
|
|
||||||
const { image, thumbnail, ...otherData } = data;
|
|
||||||
return isEqual(otherData, thisData) && image?.url === thisImage?.url && thumbnail?.url === thisThumbnail?.url;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
11
packages/builders/src/util/componentUtil.ts
Normal file
11
packages/builders/src/util/componentUtil.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import type { APIEmbed } from 'discord-api-types/v9';
|
||||||
|
|
||||||
|
export function embedLength(data: APIEmbed) {
|
||||||
|
return (
|
||||||
|
(data.title?.length ?? 0) +
|
||||||
|
(data.description?.length ?? 0) +
|
||||||
|
(data.fields?.reduce((prev, curr) => prev + curr.name.length + curr.value.length, 0) ?? 0) +
|
||||||
|
(data.footer?.text.length ?? 0) +
|
||||||
|
(data.author?.name.length ?? 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -53,6 +53,7 @@
|
|||||||
"@sapphire/snowflake": "^3.1.0",
|
"@sapphire/snowflake": "^3.1.0",
|
||||||
"@types/ws": "^8.2.2",
|
"@types/ws": "^8.2.2",
|
||||||
"discord-api-types": "^0.27.3",
|
"discord-api-types": "^0.27.3",
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
"lodash.snakecase": "^4.1.1",
|
"lodash.snakecase": "^4.1.1",
|
||||||
"undici": "^4.14.1",
|
"undici": "^4.14.1",
|
||||||
"ws": "^8.5.0"
|
"ws": "^8.5.0"
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ exports.WebSocketShard = require('./client/websocket/WebSocketShard');
|
|||||||
|
|
||||||
// Structures
|
// Structures
|
||||||
exports.ActionRow = require('./structures/ActionRow');
|
exports.ActionRow = require('./structures/ActionRow');
|
||||||
|
exports.ActionRowBuilder = require('./structures/ActionRowBuilder');
|
||||||
exports.Activity = require('./structures/Presence').Activity;
|
exports.Activity = require('./structures/Presence').Activity;
|
||||||
exports.AnonymousGuild = require('./structures/AnonymousGuild');
|
exports.AnonymousGuild = require('./structures/AnonymousGuild');
|
||||||
exports.Application = require('./structures/interfaces/Application');
|
exports.Application = require('./structures/interfaces/Application');
|
||||||
@@ -81,6 +82,7 @@ exports.BaseGuild = require('./structures/BaseGuild');
|
|||||||
exports.BaseGuildEmoji = require('./structures/BaseGuildEmoji');
|
exports.BaseGuildEmoji = require('./structures/BaseGuildEmoji');
|
||||||
exports.BaseGuildTextChannel = require('./structures/BaseGuildTextChannel');
|
exports.BaseGuildTextChannel = require('./structures/BaseGuildTextChannel');
|
||||||
exports.BaseGuildVoiceChannel = require('./structures/BaseGuildVoiceChannel');
|
exports.BaseGuildVoiceChannel = require('./structures/BaseGuildVoiceChannel');
|
||||||
|
exports.ButtonBuilder = require('./structures/ButtonBuilder');
|
||||||
exports.ButtonComponent = require('./structures/ButtonComponent');
|
exports.ButtonComponent = require('./structures/ButtonComponent');
|
||||||
exports.ButtonInteraction = require('./structures/ButtonInteraction');
|
exports.ButtonInteraction = require('./structures/ButtonInteraction');
|
||||||
exports.CategoryChannel = require('./structures/CategoryChannel');
|
exports.CategoryChannel = require('./structures/CategoryChannel');
|
||||||
@@ -92,9 +94,11 @@ exports.ClientUser = require('./structures/ClientUser');
|
|||||||
exports.CommandInteraction = require('./structures/CommandInteraction');
|
exports.CommandInteraction = require('./structures/CommandInteraction');
|
||||||
exports.Collector = require('./structures/interfaces/Collector');
|
exports.Collector = require('./structures/interfaces/Collector');
|
||||||
exports.CommandInteractionOptionResolver = require('./structures/CommandInteractionOptionResolver');
|
exports.CommandInteractionOptionResolver = require('./structures/CommandInteractionOptionResolver');
|
||||||
|
exports.Component = require('./structures/Component');
|
||||||
exports.ContextMenuCommandInteraction = require('./structures/ContextMenuCommandInteraction');
|
exports.ContextMenuCommandInteraction = require('./structures/ContextMenuCommandInteraction');
|
||||||
exports.DMChannel = require('./structures/DMChannel');
|
exports.DMChannel = require('./structures/DMChannel');
|
||||||
exports.Embed = require('./structures/Embed');
|
exports.Embed = require('./structures/Embed');
|
||||||
|
exports.EmbedBuilder = require('./structures/EmbedBuilder');
|
||||||
exports.UnsafeEmbed = require('@discordjs/builders').UnsafeEmbed;
|
exports.UnsafeEmbed = require('@discordjs/builders').UnsafeEmbed;
|
||||||
exports.Emoji = require('./structures/Emoji').Emoji;
|
exports.Emoji = require('./structures/Emoji').Emoji;
|
||||||
exports.Guild = require('./structures/Guild').Guild;
|
exports.Guild = require('./structures/Guild').Guild;
|
||||||
@@ -136,6 +140,7 @@ exports.ReactionCollector = require('./structures/ReactionCollector');
|
|||||||
exports.ReactionEmoji = require('./structures/ReactionEmoji');
|
exports.ReactionEmoji = require('./structures/ReactionEmoji');
|
||||||
exports.RichPresenceAssets = require('./structures/Presence').RichPresenceAssets;
|
exports.RichPresenceAssets = require('./structures/Presence').RichPresenceAssets;
|
||||||
exports.Role = require('./structures/Role').Role;
|
exports.Role = require('./structures/Role').Role;
|
||||||
|
exports.SelectMenuBuilder = require('./structures/SelectMenuBuilder');
|
||||||
exports.SelectMenuComponent = require('./structures/SelectMenuComponent');
|
exports.SelectMenuComponent = require('./structures/SelectMenuComponent');
|
||||||
exports.SelectMenuInteraction = require('./structures/SelectMenuInteraction');
|
exports.SelectMenuInteraction = require('./structures/SelectMenuInteraction');
|
||||||
exports.StageChannel = require('./structures/StageChannel');
|
exports.StageChannel = require('./structures/StageChannel');
|
||||||
@@ -146,6 +151,7 @@ exports.StoreChannel = require('./structures/StoreChannel');
|
|||||||
exports.Team = require('./structures/Team');
|
exports.Team = require('./structures/Team');
|
||||||
exports.TeamMember = require('./structures/TeamMember');
|
exports.TeamMember = require('./structures/TeamMember');
|
||||||
exports.TextChannel = require('./structures/TextChannel');
|
exports.TextChannel = require('./structures/TextChannel');
|
||||||
|
exports.TextInputBuilder = require('./structures/TextInputBuilder');
|
||||||
exports.TextInputComponent = require('./structures/TextInputComponent');
|
exports.TextInputComponent = require('./structures/TextInputComponent');
|
||||||
exports.ThreadChannel = require('./structures/ThreadChannel');
|
exports.ThreadChannel = require('./structures/ThreadChannel');
|
||||||
exports.ThreadMember = require('./structures/ThreadMember');
|
exports.ThreadMember = require('./structures/ThreadMember');
|
||||||
@@ -191,6 +197,7 @@ exports.InviteTargetType = require('discord-api-types/v9').InviteTargetType;
|
|||||||
exports.Locale = require('discord-api-types/v9').Locale;
|
exports.Locale = require('discord-api-types/v9').Locale;
|
||||||
exports.MessageType = require('discord-api-types/v9').MessageType;
|
exports.MessageType = require('discord-api-types/v9').MessageType;
|
||||||
exports.MessageFlags = require('discord-api-types/v9').MessageFlags;
|
exports.MessageFlags = require('discord-api-types/v9').MessageFlags;
|
||||||
|
exports.ModalBuilder = require('@discordjs/builders').ModalBuilder;
|
||||||
exports.OAuth2Scopes = require('discord-api-types/v9').OAuth2Scopes;
|
exports.OAuth2Scopes = require('discord-api-types/v9').OAuth2Scopes;
|
||||||
exports.PermissionFlagsBits = require('discord-api-types/v9').PermissionFlagsBits;
|
exports.PermissionFlagsBits = require('discord-api-types/v9').PermissionFlagsBits;
|
||||||
exports.RESTJSONErrorCodes = require('discord-api-types/v9').RESTJSONErrorCodes;
|
exports.RESTJSONErrorCodes = require('discord-api-types/v9').RESTJSONErrorCodes;
|
||||||
@@ -200,10 +207,10 @@ exports.StickerFormatType = require('discord-api-types/v9').StickerFormatType;
|
|||||||
exports.TextInputStyle = require('discord-api-types/v9').TextInputStyle;
|
exports.TextInputStyle = require('discord-api-types/v9').TextInputStyle;
|
||||||
exports.UserFlags = require('discord-api-types/v9').UserFlags;
|
exports.UserFlags = require('discord-api-types/v9').UserFlags;
|
||||||
exports.WebhookType = require('discord-api-types/v9').WebhookType;
|
exports.WebhookType = require('discord-api-types/v9').WebhookType;
|
||||||
exports.UnsafeButtonComponent = require('@discordjs/builders').UnsafeButtonComponent;
|
exports.UnsafeButtonBuilder = require('@discordjs/builders').UnsafeButtonBuilder;
|
||||||
exports.UnsafeSelectMenuComponent = require('@discordjs/builders').UnsafeSelectMenuComponent;
|
exports.UnsafeSelectMenuBuilder = require('@discordjs/builders').UnsafeSelectMenuBuilder;
|
||||||
exports.SelectMenuOption = require('@discordjs/builders').SelectMenuOption;
|
exports.SelectMenuOptionBuilder = require('@discordjs/builders').SelectMenuOptionBuilder;
|
||||||
exports.UnsafeSelectMenuOption = require('@discordjs/builders').UnsafeSelectMenuOption;
|
exports.UnsafeSelectMenuOptionBuilder = require('@discordjs/builders').UnsafeSelectMenuOptionBuilder;
|
||||||
exports.DiscordAPIError = require('@discordjs/rest').DiscordAPIError;
|
exports.DiscordAPIError = require('@discordjs/rest').DiscordAPIError;
|
||||||
exports.HTTPError = require('@discordjs/rest').HTTPError;
|
exports.HTTPError = require('@discordjs/rest').HTTPError;
|
||||||
exports.RateLimitError = require('@discordjs/rest').RateLimitError;
|
exports.RateLimitError = require('@discordjs/rest').RateLimitError;
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { ActionRow: BuildersActionRow, Component } = require('@discordjs/builders');
|
const Component = require('./Component');
|
||||||
const Transformers = require('../util/Transformers');
|
const Components = require('../util/Components');
|
||||||
|
|
||||||
class ActionRow extends BuildersActionRow {
|
/**
|
||||||
constructor({ components, ...data } = {}) {
|
* Represents an action row
|
||||||
super({
|
* @extends {Component}
|
||||||
components: components?.map(c => (c instanceof Component ? c : Transformers.toSnakeCase(c))),
|
*/
|
||||||
...Transformers.toSnakeCase(data),
|
class ActionRow extends Component {
|
||||||
});
|
constructor({ components, ...data }) {
|
||||||
|
super(data);
|
||||||
|
/**
|
||||||
|
* The components in this action row
|
||||||
|
* @type {Component[]}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.components = components.map(c => Components.createComponent(c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
15
packages/discord.js/src/structures/ActionRowBuilder.js
Normal file
15
packages/discord.js/src/structures/ActionRowBuilder.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { ActionRowBuilder: BuildersActionRow, ComponentBuilder } = require('@discordjs/builders');
|
||||||
|
const Transformers = require('../util/Transformers');
|
||||||
|
|
||||||
|
class ActionRowBuilder extends BuildersActionRow {
|
||||||
|
constructor({ components, ...data } = {}) {
|
||||||
|
super({
|
||||||
|
components: components?.map(c => (c instanceof ComponentBuilder ? c : Transformers.toSnakeCase(c))),
|
||||||
|
...Transformers.toSnakeCase(data),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ActionRowBuilder;
|
||||||
24
packages/discord.js/src/structures/ButtonBuilder.js
Normal file
24
packages/discord.js/src/structures/ButtonBuilder.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { ButtonBuilder: BuildersButtonComponent, isJSONEncodable } = require('@discordjs/builders');
|
||||||
|
const Transformers = require('../util/Transformers');
|
||||||
|
|
||||||
|
class ButtonBuilder extends BuildersButtonComponent {
|
||||||
|
constructor(data) {
|
||||||
|
super(Transformers.toSnakeCase(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new button builder from json data
|
||||||
|
* @param {JSONEncodable<APIButtonComponent> | APIButtonComponent} other The other data
|
||||||
|
* @returns {ButtonBuilder}
|
||||||
|
*/
|
||||||
|
static from(other) {
|
||||||
|
if (isJSONEncodable(other)) {
|
||||||
|
return new this(other.toJSON());
|
||||||
|
}
|
||||||
|
return new this(other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ButtonBuilder;
|
||||||
@@ -1,11 +1,64 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { ButtonComponent: BuildersButtonComponent } = require('@discordjs/builders');
|
const Component = require('./Component');
|
||||||
const Transformers = require('../util/Transformers');
|
|
||||||
|
|
||||||
class ButtonComponent extends BuildersButtonComponent {
|
/**
|
||||||
constructor(data) {
|
* Represents a button component
|
||||||
super(Transformers.toSnakeCase(data));
|
* @extends {Component}
|
||||||
|
*/
|
||||||
|
class ButtonComponent extends Component {
|
||||||
|
/**
|
||||||
|
* The style of this button
|
||||||
|
* @type {ButtonStyle}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get style() {
|
||||||
|
return this.data.style;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The label of this button
|
||||||
|
* @type {?string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get label() {
|
||||||
|
return this.data.label ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The emoji used in this button
|
||||||
|
* @type {?APIMessageComponentEmoji}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get emoji() {
|
||||||
|
return this.data.emoji ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this button is disabled
|
||||||
|
* @type {?boolean}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get disabled() {
|
||||||
|
return this.data.disabled ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The custom id of this button (only defined on non-link buttons)
|
||||||
|
* @type {?string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get customId() {
|
||||||
|
return this.data.custom_id ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL of this button (only defined on link buttons)
|
||||||
|
* @type {?string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get url() {
|
||||||
|
return this.data.url ?? null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
52
packages/discord.js/src/structures/Component.js
Normal file
52
packages/discord.js/src/structures/Component.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const isEqual = require('fast-deep-equal');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a component
|
||||||
|
*/
|
||||||
|
class Component {
|
||||||
|
/**
|
||||||
|
* Creates a new component from API data
|
||||||
|
* @param {APIMessageComponent} data The API component data
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
constructor(data) {
|
||||||
|
/**
|
||||||
|
* The API data associated with this component
|
||||||
|
* @type {APIMessageComponent}
|
||||||
|
*/
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the component
|
||||||
|
* @type {ComponentType}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get type() {
|
||||||
|
return this.data.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the given components are equal
|
||||||
|
* @param {Component|APIMessageComponent} other The component to compare against
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
equals(other) {
|
||||||
|
if (other instanceof Component) {
|
||||||
|
return isEqual(other.data, this.data);
|
||||||
|
}
|
||||||
|
return isEqual(other, this.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the API-compatible JSON for this component
|
||||||
|
* @returns {APIMessageComponent}
|
||||||
|
*/
|
||||||
|
toJSON() {
|
||||||
|
return { ...this.data };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Component;
|
||||||
@@ -1,15 +1,198 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { Embed: BuildersEmbed } = require('@discordjs/builders');
|
const isEqual = require('fast-deep-equal');
|
||||||
const Transformers = require('../util/Transformers');
|
const { Util } = require('../util/Util');
|
||||||
const Util = require('../util/Util');
|
|
||||||
|
|
||||||
/**
|
class Embed {
|
||||||
* Represents an embed object
|
/**
|
||||||
*/
|
* Creates a new embed object
|
||||||
class Embed extends BuildersEmbed {
|
* @param {APIEmbed} data API embed data
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
constructor(data) {
|
constructor(data) {
|
||||||
super(Transformers.toSnakeCase(data));
|
/**
|
||||||
|
* The API embed data
|
||||||
|
* @type {APIEmbed}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.data = { ...data };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of fields of this embed
|
||||||
|
* @type {?Array<APIEmbedField>}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get fields() {
|
||||||
|
return this.data.fields ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The embed title
|
||||||
|
* @type {?string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get title() {
|
||||||
|
return this.data.title ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The embed description
|
||||||
|
* @type {?string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get description() {
|
||||||
|
return this.data.description ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The embed URL
|
||||||
|
* @type {?string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get url() {
|
||||||
|
return this.data.url ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The embed color
|
||||||
|
* @type {?number}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get color() {
|
||||||
|
return this.data.color ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The timestamp of the embed in an ISO 8601 format
|
||||||
|
* @type {?string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get timestamp() {
|
||||||
|
return this.data.timestamp ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The embed thumbnail data
|
||||||
|
* @type {?EmbedImageData}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get thumbnail() {
|
||||||
|
if (!this.data.thumbnail) return null;
|
||||||
|
return {
|
||||||
|
url: this.data.thumbnail.url,
|
||||||
|
proxyURL: this.data.thumbnail.proxy_url,
|
||||||
|
height: this.data.thumbnail.height,
|
||||||
|
width: this.data.thumbnail.width,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The embed image data
|
||||||
|
* @type {?EmbedImageData}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get image() {
|
||||||
|
if (!this.data.image) return null;
|
||||||
|
return {
|
||||||
|
url: this.data.image.url,
|
||||||
|
proxyURL: this.data.image.proxy_url,
|
||||||
|
height: this.data.image.height,
|
||||||
|
width: this.data.image.width,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Received video data
|
||||||
|
* @type {?EmbedVideoData}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get video() {
|
||||||
|
return this.data.video ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The embed author data
|
||||||
|
* @type {?EmbedAuthorData}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get author() {
|
||||||
|
if (!this.data.author) return null;
|
||||||
|
return {
|
||||||
|
name: this.data.author.name,
|
||||||
|
url: this.data.author.url,
|
||||||
|
iconURL: this.data.author.icon_url,
|
||||||
|
proxyIconURL: this.data.author.proxy_icon_url,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Received data about the embed provider
|
||||||
|
* @type {?EmbedProvider}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get provider() {
|
||||||
|
return this.data.provider ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The embed footer data
|
||||||
|
* @type {?EmbedFooterData}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get footer() {
|
||||||
|
if (!this.data.footer) return null;
|
||||||
|
return {
|
||||||
|
text: this.data.footer.text,
|
||||||
|
iconURL: this.data.footer.icon_url,
|
||||||
|
proxyIconURL: this.data.footer.proxy_icon_url,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The accumulated length for the embed title, description, fields, footer text, and author name
|
||||||
|
* @type {number}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get length() {
|
||||||
|
return (
|
||||||
|
(this.data.title?.length ?? 0) +
|
||||||
|
(this.data.description?.length ?? 0) +
|
||||||
|
(this.data.fields?.reduce((prev, curr) => prev + curr.name.length + curr.value.length, 0) ?? 0) +
|
||||||
|
(this.data.footer?.text.length ?? 0) +
|
||||||
|
(this.data.author?.name.length ?? 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The hex color of the current color of the embed
|
||||||
|
* @type {?string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get hexColor() {
|
||||||
|
return typeof this.data.color === 'number'
|
||||||
|
? `#${this.data.color.toString(16).padStart(6, '0')}`
|
||||||
|
: this.data.color ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the API-compatible JSON for this embed
|
||||||
|
* @returns {APIEmbed}
|
||||||
|
*/
|
||||||
|
toJSON() {
|
||||||
|
return { ...this.data };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the given embeds are equal
|
||||||
|
* @param {Embed|APIEmbed} other The embed to compare against
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
equals(other) {
|
||||||
|
if (other instanceof Embed) {
|
||||||
|
return isEqual(other.data, this.data);
|
||||||
|
}
|
||||||
|
return isEqual(other, this.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
24
packages/discord.js/src/structures/EmbedBuilder.js
Normal file
24
packages/discord.js/src/structures/EmbedBuilder.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { EmbedBuilder: BuildersEmbed, isJSONEncodable } = require('@discordjs/builders');
|
||||||
|
const Transformers = require('../util/Transformers');
|
||||||
|
|
||||||
|
class EmbedBuilder extends BuildersEmbed {
|
||||||
|
constructor(data) {
|
||||||
|
super(Transformers.toSnakeCase(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new embed builder from json data
|
||||||
|
* @param {JSONEncodable<APIEmbed> | APIEmbed} other The other data
|
||||||
|
* @returns {EmbedBuilder}
|
||||||
|
*/
|
||||||
|
static from(other) {
|
||||||
|
if (isJSONEncodable(other)) {
|
||||||
|
return new this(other.toJSON());
|
||||||
|
}
|
||||||
|
return new this(other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = EmbedBuilder;
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { createComponent, Embed } = require('@discordjs/builders');
|
|
||||||
const { Collection } = require('@discordjs/collection');
|
const { Collection } = require('@discordjs/collection');
|
||||||
const { DiscordSnowflake } = require('@sapphire/snowflake');
|
const { DiscordSnowflake } = require('@sapphire/snowflake');
|
||||||
const {
|
const {
|
||||||
@@ -12,6 +11,7 @@ const {
|
|||||||
} = require('discord-api-types/v9');
|
} = require('discord-api-types/v9');
|
||||||
const Base = require('./Base');
|
const Base = require('./Base');
|
||||||
const ClientApplication = require('./ClientApplication');
|
const ClientApplication = require('./ClientApplication');
|
||||||
|
const Embed = require('./Embed');
|
||||||
const InteractionCollector = require('./InteractionCollector');
|
const InteractionCollector = require('./InteractionCollector');
|
||||||
const MessageAttachment = require('./MessageAttachment');
|
const MessageAttachment = require('./MessageAttachment');
|
||||||
const Mentions = require('./MessageMentions');
|
const Mentions = require('./MessageMentions');
|
||||||
@@ -20,6 +20,7 @@ const ReactionCollector = require('./ReactionCollector');
|
|||||||
const { Sticker } = require('./Sticker');
|
const { Sticker } = require('./Sticker');
|
||||||
const { Error } = require('../errors');
|
const { Error } = require('../errors');
|
||||||
const ReactionManager = require('../managers/ReactionManager');
|
const ReactionManager = require('../managers/ReactionManager');
|
||||||
|
const Components = require('../util/Components');
|
||||||
const { NonSystemMessageTypes } = require('../util/Constants');
|
const { NonSystemMessageTypes } = require('../util/Constants');
|
||||||
const MessageFlagsBitField = require('../util/MessageFlagsBitField');
|
const MessageFlagsBitField = require('../util/MessageFlagsBitField');
|
||||||
const PermissionsBitField = require('../util/PermissionsBitField');
|
const PermissionsBitField = require('../util/PermissionsBitField');
|
||||||
@@ -145,7 +146,7 @@ class Message extends Base {
|
|||||||
* A list of MessageActionRows in the message
|
* A list of MessageActionRows in the message
|
||||||
* @type {ActionRow[]}
|
* @type {ActionRow[]}
|
||||||
*/
|
*/
|
||||||
this.components = data.components.map(c => createComponent(c));
|
this.components = data.components.map(c => Components.createComponent(c));
|
||||||
} else {
|
} else {
|
||||||
this.components = this.components?.slice() ?? [];
|
this.components = this.components?.slice() ?? [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const { Modal: BuildersModal } = require('@discordjs/builders');
|
|
||||||
const Transformers = require('../util/Transformers');
|
|
||||||
|
|
||||||
class Modal extends BuildersModal {
|
|
||||||
constructor(data) {
|
|
||||||
super(Transformers.toSnakeCase(data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Modal;
|
|
||||||
24
packages/discord.js/src/structures/SelectMenuBuilder.js
Normal file
24
packages/discord.js/src/structures/SelectMenuBuilder.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { SelectMenuBuilder: BuildersSelectMenuComponent, isJSONEncodable } = require('@discordjs/builders');
|
||||||
|
const Transformers = require('../util/Transformers');
|
||||||
|
|
||||||
|
class SelectMenuBuilder extends BuildersSelectMenuComponent {
|
||||||
|
constructor(data) {
|
||||||
|
super(Transformers.toSnakeCase(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new select menu builder from json data
|
||||||
|
* @param {JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent} other The other data
|
||||||
|
* @returns {SelectMenuBuilder}
|
||||||
|
*/
|
||||||
|
static from(other) {
|
||||||
|
if (isJSONEncodable(other)) {
|
||||||
|
return new this(other.toJSON());
|
||||||
|
}
|
||||||
|
return new this(other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = SelectMenuBuilder;
|
||||||
@@ -1,11 +1,64 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { SelectMenuComponent: BuildersSelectMenuComponent } = require('@discordjs/builders');
|
const Component = require('./Component');
|
||||||
const Transformers = require('../util/Transformers');
|
|
||||||
|
|
||||||
class SelectMenuComponent extends BuildersSelectMenuComponent {
|
/**
|
||||||
constructor(data) {
|
* Represents a select menu component
|
||||||
super(Transformers.toSnakeCase(data));
|
* @extends {Component}
|
||||||
|
*/
|
||||||
|
class SelectMenuComponent extends Component {
|
||||||
|
/**
|
||||||
|
* The placeholder for this select menu
|
||||||
|
* @type {?string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get placeholder() {
|
||||||
|
return this.data.placeholder ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum amount of options that can be selected
|
||||||
|
* @type {?number}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get maxValues() {
|
||||||
|
return this.data.max_values ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum amount of options that must be selected
|
||||||
|
* @type {?number}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get minValues() {
|
||||||
|
return this.data.min_values ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The custom id of this select menu
|
||||||
|
* @type {string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get customId() {
|
||||||
|
return this.data.custom_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this select menu is disabled
|
||||||
|
* @type {?boolean}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get disabled() {
|
||||||
|
return this.data.disabled ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The options in this select menu
|
||||||
|
* @type {APISelectMenuOption[]}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get options() {
|
||||||
|
return this.data.options;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
24
packages/discord.js/src/structures/TextInputBuilder.js
Normal file
24
packages/discord.js/src/structures/TextInputBuilder.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { TextInputBuilder: BuildersTextInputComponent, isJSONEncodable } = require('@discordjs/builders');
|
||||||
|
const Transformers = require('../util/Transformers');
|
||||||
|
|
||||||
|
class TextInputBuilder extends BuildersTextInputComponent {
|
||||||
|
constructor(data) {
|
||||||
|
super(Transformers.toSnakeCase(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new text input builder from json data
|
||||||
|
* @param {JSONEncodable<APITextInputComponent> | APITextInputComponent} other The other data
|
||||||
|
* @returns {TextInputBuilder}
|
||||||
|
*/
|
||||||
|
static from(other) {
|
||||||
|
if (isJSONEncodable(other)) {
|
||||||
|
return new this(other.toJSON());
|
||||||
|
}
|
||||||
|
return new this(other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TextInputBuilder;
|
||||||
@@ -1,11 +1,20 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { TextInputComponent: BuildersTextInputComponent } = require('@discordjs/builders');
|
const Component = require('./Component');
|
||||||
const Transformers = require('../util/Transformers');
|
|
||||||
|
|
||||||
class TextInputComponent extends BuildersTextInputComponent {
|
class TextInputComponent extends Component {
|
||||||
constructor(data) {
|
/**
|
||||||
super(Transformers.toSnakeCase(data));
|
* The custom id of this text input
|
||||||
|
*/
|
||||||
|
get customId() {
|
||||||
|
return this.data.custom_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value for this text input
|
||||||
|
*/
|
||||||
|
get value() {
|
||||||
|
return this.data.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// This file contains the typedefs for camel-cased json data
|
// This file contains the typedefs for camel-cased json data
|
||||||
|
const { ComponentType } = require('discord-api-types/v9');
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} BaseComponentData
|
* @typedef {Object} BaseComponentData
|
||||||
* @property {ComponentType} type The type of component
|
* @property {ComponentType} type The type of component
|
||||||
@@ -56,3 +56,34 @@
|
|||||||
/**
|
/**
|
||||||
* @typedef {ActionRowData|ButtonComponentData|SelectMenuComponentData|TextInputComponentData} ComponentData
|
* @typedef {ActionRowData|ButtonComponentData|SelectMenuComponentData|TextInputComponentData} ComponentData
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
class Components extends null {
|
||||||
|
/**
|
||||||
|
* Transforms API data into a component
|
||||||
|
* @param {APIMessageComponent|Component} data The data to create the component from
|
||||||
|
* @returns {Component}
|
||||||
|
*/
|
||||||
|
static createComponent(data) {
|
||||||
|
if (data instanceof Component) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (data.type) {
|
||||||
|
case ComponentType.ActionRow:
|
||||||
|
return new ActionRow(data);
|
||||||
|
case ComponentType.Button:
|
||||||
|
return new ButtonComponent(data);
|
||||||
|
case ComponentType.SelectMenu:
|
||||||
|
return new SelectMenuComponent(data);
|
||||||
|
default:
|
||||||
|
throw new Error(`Found unknown component type: ${data.type}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Components;
|
||||||
|
|
||||||
|
const ActionRow = require('../structures/ActionRow');
|
||||||
|
const ButtonComponent = require('../structures/ButtonComponent');
|
||||||
|
const Component = require('../structures/Component');
|
||||||
|
const SelectMenuComponent = require('../structures/SelectMenuComponent');
|
||||||
|
|||||||
185
packages/discord.js/typings/index.d.ts
vendored
185
packages/discord.js/typings/index.d.ts
vendored
@@ -1,24 +1,24 @@
|
|||||||
import {
|
import {
|
||||||
ActionRow as BuilderActionRow,
|
ActionRowBuilder as BuilderActionRow,
|
||||||
MessageActionRowComponent,
|
MessageActionRowComponentBuilder,
|
||||||
blockQuote,
|
blockQuote,
|
||||||
bold,
|
bold,
|
||||||
ButtonComponent as BuilderButtonComponent,
|
ButtonBuilder as BuilderButtonComponent,
|
||||||
channelMention,
|
channelMention,
|
||||||
codeBlock,
|
codeBlock,
|
||||||
Component,
|
EmbedBuilder as BuildersEmbed,
|
||||||
Embed as BuildersEmbed,
|
|
||||||
formatEmoji,
|
formatEmoji,
|
||||||
hideLinkEmbed,
|
hideLinkEmbed,
|
||||||
hyperlink,
|
hyperlink,
|
||||||
inlineCode,
|
inlineCode,
|
||||||
italic,
|
italic,
|
||||||
|
JSONEncodable,
|
||||||
|
MappedComponentTypes,
|
||||||
memberNicknameMention,
|
memberNicknameMention,
|
||||||
Modal as BuilderModal,
|
|
||||||
quote,
|
quote,
|
||||||
roleMention,
|
roleMention,
|
||||||
SelectMenuComponent as BuilderSelectMenuComponent,
|
SelectMenuBuilder as BuilderSelectMenuComponent,
|
||||||
TextInputComponent as BuilderTextInputComponent,
|
TextInputBuilder as BuilderTextInputComponent,
|
||||||
spoiler,
|
spoiler,
|
||||||
strikethrough,
|
strikethrough,
|
||||||
time,
|
time,
|
||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
TimestampStylesString,
|
TimestampStylesString,
|
||||||
underscore,
|
underscore,
|
||||||
userMention,
|
userMention,
|
||||||
ModalActionRowComponent,
|
ModalActionRowComponentBuilder,
|
||||||
} from '@discordjs/builders';
|
} from '@discordjs/builders';
|
||||||
import { Collection } from '@discordjs/collection';
|
import { Collection } from '@discordjs/collection';
|
||||||
import { BaseImageURLOptions, ImageURLOptions, RawFile, REST, RESTOptions } from '@discordjs/rest';
|
import { BaseImageURLOptions, ImageURLOptions, RawFile, REST, RESTOptions } from '@discordjs/rest';
|
||||||
@@ -105,6 +105,11 @@ import {
|
|||||||
APITextInputComponent,
|
APITextInputComponent,
|
||||||
APIModalActionRowComponent,
|
APIModalActionRowComponent,
|
||||||
APIModalComponent,
|
APIModalComponent,
|
||||||
|
APISelectMenuOption,
|
||||||
|
APIEmbedField,
|
||||||
|
APIEmbedAuthor,
|
||||||
|
APIEmbedFooter,
|
||||||
|
APIEmbedImage,
|
||||||
} from 'discord-api-types/v9';
|
} from 'discord-api-types/v9';
|
||||||
import { ChildProcess } from 'node:child_process';
|
import { ChildProcess } from 'node:child_process';
|
||||||
import { EventEmitter } from 'node:events';
|
import { EventEmitter } from 'node:events';
|
||||||
@@ -220,8 +225,10 @@ export interface ActionRowData<T extends ActionRowComponent | ActionRowComponent
|
|||||||
components: T[];
|
components: T[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ActionRow<
|
export class ActionRowBuilder<
|
||||||
T extends MessageActionRowComponent | ModalActionRowComponent = MessageActionRowComponent,
|
T extends MessageActionRowComponentBuilder | ModalActionRowComponentBuilder =
|
||||||
|
| MessageActionRowComponentBuilder
|
||||||
|
| ModalActionRowComponentBuilder,
|
||||||
> extends BuilderActionRow<T> {
|
> extends BuilderActionRow<T> {
|
||||||
constructor(
|
constructor(
|
||||||
data?:
|
data?:
|
||||||
@@ -232,6 +239,14 @@ export class ActionRow<
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type MessageActionRowComponent = ButtonComponent | SelectMenuComponent;
|
||||||
|
export type ModalActionRowComponent = TextInputComponent;
|
||||||
|
|
||||||
|
export class ActionRow<T extends MessageActionRowComponent | ModalActionRowComponent> {
|
||||||
|
private constructor(data: APIActionRowComponent<APIMessageActionRowComponent>);
|
||||||
|
public readonly components: T[];
|
||||||
|
}
|
||||||
|
|
||||||
export class ActivityFlagsBitField extends BitField<ActivityFlagsString> {
|
export class ActivityFlagsBitField extends BitField<ActivityFlagsString> {
|
||||||
public static Flags: typeof ActivityFlags;
|
public static Flags: typeof ActivityFlags;
|
||||||
public static resolve(bit?: BitFieldResolvable<ActivityFlagsString, number>): number;
|
public static resolve(bit?: BitFieldResolvable<ActivityFlagsString, number>): number;
|
||||||
@@ -356,7 +371,9 @@ export interface InteractionResponseFields<Cached extends CacheType = CacheType>
|
|||||||
deferReply(options?: InteractionDeferReplyOptions): Promise<void>;
|
deferReply(options?: InteractionDeferReplyOptions): Promise<void>;
|
||||||
fetchReply(): Promise<GuildCacheMessage<Cached>>;
|
fetchReply(): Promise<GuildCacheMessage<Cached>>;
|
||||||
followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<GuildCacheMessage<Cached>>;
|
followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<GuildCacheMessage<Cached>>;
|
||||||
showModal(modal: Modal | ModalData | APIModalInteractionResponseCallbackData): Promise<void>;
|
showModal(
|
||||||
|
modal: JSONEncodable<APIModalInteractionResponseCallbackData> | ModalData | APIModalInteractionResponseCallbackData,
|
||||||
|
): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class CommandInteraction<Cached extends CacheType = CacheType> extends Interaction<Cached> {
|
export abstract class CommandInteraction<Cached extends CacheType = CacheType> extends Interaction<Cached> {
|
||||||
@@ -395,7 +412,9 @@ export abstract class CommandInteraction<Cached extends CacheType = CacheType> e
|
|||||||
public followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<GuildCacheMessage<Cached>>;
|
public followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<GuildCacheMessage<Cached>>;
|
||||||
public reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
|
public reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
|
||||||
public reply(options: string | MessagePayload | InteractionReplyOptions): Promise<void>;
|
public reply(options: string | MessagePayload | InteractionReplyOptions): Promise<void>;
|
||||||
public showModal(modal: Modal | ModalData | APIModalInteractionResponseCallbackData): Promise<void>;
|
public showModal(
|
||||||
|
modal: JSONEncodable<APIModalInteractionResponseCallbackData> | ModalData | APIModalInteractionResponseCallbackData,
|
||||||
|
): Promise<void>;
|
||||||
private transformOption(
|
private transformOption(
|
||||||
option: APIApplicationCommandOption,
|
option: APIApplicationCommandOption,
|
||||||
resolved: APIApplicationCommandInteractionData['resolved'],
|
resolved: APIApplicationCommandInteractionData['resolved'],
|
||||||
@@ -502,22 +521,53 @@ export class ButtonInteraction<Cached extends CacheType = CacheType> extends Mes
|
|||||||
public inRawGuild(): this is ButtonInteraction<'raw'>;
|
public inRawGuild(): this is ButtonInteraction<'raw'>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ButtonComponent extends BuilderButtonComponent {
|
export class Component<T extends APIMessageComponent | APIModalComponent = APIMessageComponent | APIModalComponent> {
|
||||||
public constructor(data?: ButtonComponentData | (Omit<APIButtonComponent, 'type'> & { type?: ComponentType.Button }));
|
public readonly data: Readonly<T>;
|
||||||
|
public get type(): T['type'];
|
||||||
|
public toJSON(): T;
|
||||||
|
public equals(other: this | T): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SelectMenuComponent extends BuilderSelectMenuComponent {
|
export class ButtonComponent extends Component<APIButtonComponent> {
|
||||||
|
private constructor(data: APIButtonComponent);
|
||||||
|
public get style(): ButtonStyle;
|
||||||
|
public get label(): string | null;
|
||||||
|
public get emoji(): APIMessageComponentEmoji | null;
|
||||||
|
public get disabled(): boolean | null;
|
||||||
|
public get customId(): string | null;
|
||||||
|
public get url(): string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ButtonBuilder extends BuilderButtonComponent {
|
||||||
|
public constructor(data?: ButtonComponentData | (Omit<APIButtonComponent, 'type'> & { type?: ComponentType.Button }));
|
||||||
|
public static from(other: JSONEncodable<APIButtonComponent> | APIButtonComponent): ButtonBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SelectMenuBuilder extends BuilderSelectMenuComponent {
|
||||||
public constructor(
|
public constructor(
|
||||||
data?: SelectMenuComponentData | (Omit<APISelectMenuComponent, 'type'> & { type?: ComponentType.SelectMenu }),
|
data?: SelectMenuComponentData | (Omit<APISelectMenuComponent, 'type'> & { type?: ComponentType.SelectMenu }),
|
||||||
);
|
);
|
||||||
|
public static from(other: JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent): SelectMenuBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TextInputComponent extends BuilderTextInputComponent {
|
export class TextInputBuilder extends BuilderTextInputComponent {
|
||||||
public constructor(data?: TextInputComponentData | APITextInputComponent);
|
public constructor(data?: TextInputComponentData | APITextInputComponent);
|
||||||
|
public static from(other: JSONEncodable<APITextInputComponent> | APITextInputComponent): TextInputBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Modal extends BuilderModal {
|
export class TextInputComponent extends Component<APITextInputComponent> {
|
||||||
public constructor(data?: ModalData | APIModalActionRowComponent);
|
public get customId(): string;
|
||||||
|
public get value(): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SelectMenuComponent extends Component<APISelectMenuComponent> {
|
||||||
|
private constructor(data: APISelectMenuComponent);
|
||||||
|
public get placeholder(): string | null;
|
||||||
|
public get maxValues(): number | null;
|
||||||
|
public get minValues(): number | null;
|
||||||
|
public get customId(): string;
|
||||||
|
public get disabled(): boolean | null;
|
||||||
|
public get options(): APISelectMenuOption[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EmbedData {
|
export interface EmbedData {
|
||||||
@@ -535,18 +585,43 @@ export interface EmbedData {
|
|||||||
fields?: EmbedFieldData[];
|
fields?: EmbedFieldData[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EmbedImageData {
|
export interface IconData {
|
||||||
url?: string;
|
iconURL?: string;
|
||||||
|
proxyIconURL?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type EmbedAuthorData = Omit<APIEmbedAuthor, 'icon_url' | 'proxy_icon_url'> & IconData;
|
||||||
|
|
||||||
|
export type EmbedFooterData = Omit<APIEmbedFooter, 'icon_url' | 'proxy_icon_url'> & IconData;
|
||||||
|
|
||||||
export interface EmbedProviderData {
|
export interface EmbedProviderData {
|
||||||
name?: string;
|
name?: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Embed extends BuildersEmbed {
|
export interface EmbedImageData extends Omit<APIEmbedImage, 'proxy_url'> {
|
||||||
|
proxyURL?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class EmbedBuilder extends BuildersEmbed {
|
||||||
public constructor(data?: EmbedData | APIEmbed);
|
public constructor(data?: EmbedData | APIEmbed);
|
||||||
public override setColor(color: ColorResolvable | null): this;
|
public override setColor(color: ColorResolvable | null): this;
|
||||||
|
public static from(other: JSONEncodable<APIEmbed> | APIEmbed): EmbedBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Embed {
|
||||||
|
private constructor(data: APIEmbed);
|
||||||
|
public readonly data: Readonly<APIEmbed>;
|
||||||
|
public get fields(): APIEmbedField[] | null;
|
||||||
|
public get title(): string | null;
|
||||||
|
public get description(): string | null;
|
||||||
|
public get url(): string | null;
|
||||||
|
public get color(): number | null;
|
||||||
|
public get timestamp(): string | null;
|
||||||
|
public get thumbnail(): EmbedImageData | null;
|
||||||
|
public get image(): EmbedImageData | null;
|
||||||
|
public equals(other: Embed | APIEmbed): boolean;
|
||||||
|
public toJSON(): APIEmbed;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MappedChannelCategoryTypes {
|
export interface MappedChannelCategoryTypes {
|
||||||
@@ -1652,7 +1727,9 @@ export class MessageComponentInteraction<Cached extends CacheType = CacheType> e
|
|||||||
public reply(options: string | MessagePayload | InteractionReplyOptions): Promise<void>;
|
public reply(options: string | MessagePayload | InteractionReplyOptions): Promise<void>;
|
||||||
public update(options: InteractionUpdateOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
|
public update(options: InteractionUpdateOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
|
||||||
public update(options: string | MessagePayload | InteractionUpdateOptions): Promise<void>;
|
public update(options: string | MessagePayload | InteractionUpdateOptions): Promise<void>;
|
||||||
public showModal(modal: Modal | ModalData | APIModalInteractionResponseCallbackData): Promise<void>;
|
public showModal(
|
||||||
|
modal: JSONEncodable<APIModalInteractionResponseCallbackData> | ModalData | APIModalInteractionResponseCallbackData,
|
||||||
|
): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MessageContextMenuCommandInteraction<
|
export class MessageContextMenuCommandInteraction<
|
||||||
@@ -1741,17 +1818,11 @@ export class MessageReaction {
|
|||||||
public toJSON(): unknown;
|
public toJSON(): unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ModalFieldData {
|
|
||||||
value: string;
|
|
||||||
type: ComponentType;
|
|
||||||
customId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ModalSubmitFieldsResolver {
|
export class ModalSubmitFieldsResolver {
|
||||||
constructor(components: ModalFieldData[][]);
|
constructor(components: ModalActionRowComponent[][]);
|
||||||
public components: ModalFieldData[][];
|
public components: ActionRow<ModalActionRowComponent>;
|
||||||
public fields: Collection<string, ModalFieldData>;
|
public fields: Collection<string, ModalActionRowComponent>;
|
||||||
public getField(customId: string): ModalFieldData;
|
public getField(customId: string): ModalActionRowComponent;
|
||||||
public getTextInputValue(customId: string): string;
|
public getTextInputValue(customId: string): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1769,7 +1840,7 @@ export interface ModalMessageModalSubmitInteraction<Cached extends CacheType = C
|
|||||||
|
|
||||||
export interface ModalSubmitActionRow {
|
export interface ModalSubmitActionRow {
|
||||||
type: ComponentType.ActionRow;
|
type: ComponentType.ActionRow;
|
||||||
components: ModalFieldData[];
|
components: ActionRow<TextInputComponent>[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ModalSubmitInteraction<Cached extends CacheType = CacheType> extends Interaction<Cached> {
|
export class ModalSubmitInteraction<Cached extends CacheType = CacheType> extends Interaction<Cached> {
|
||||||
@@ -2452,6 +2523,14 @@ export class Util extends null {
|
|||||||
public static splitMessage(text: string, options?: SplitOptions): string[];
|
public static splitMessage(text: string, options?: SplitOptions): string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class Components extends null {
|
||||||
|
public static createComponentBuilder<T extends keyof MappedComponentTypes>(
|
||||||
|
data: APIMessageComponent & { type: T },
|
||||||
|
): MappedComponentTypes[T];
|
||||||
|
public static createComponentBuilder<C extends Component>(data: C): C;
|
||||||
|
public static createComponentBuilder(data: APIMessageComponent | Component): Component;
|
||||||
|
}
|
||||||
|
|
||||||
export class Formatters extends null {
|
export class Formatters extends null {
|
||||||
public static blockQuote: typeof blockQuote;
|
public static blockQuote: typeof blockQuote;
|
||||||
public static bold: typeof bold;
|
public static bold: typeof bold;
|
||||||
@@ -3966,12 +4045,6 @@ export interface EditGuildTemplateOptions {
|
|||||||
description?: string;
|
description?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EmbedAuthorData {
|
|
||||||
name: string;
|
|
||||||
url?: string;
|
|
||||||
iconURL?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EmbedField {
|
export interface EmbedField {
|
||||||
name: string;
|
name: string;
|
||||||
value: string;
|
value: string;
|
||||||
@@ -3984,11 +4057,6 @@ export interface EmbedFieldData {
|
|||||||
inline?: boolean;
|
inline?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EmbedFooterData {
|
|
||||||
text: string;
|
|
||||||
iconURL?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type EmojiIdentifierResolvable = string | EmojiResolvable;
|
export type EmojiIdentifierResolvable = string | EmojiResolvable;
|
||||||
|
|
||||||
export type EmojiResolvable = Snowflake | GuildEmoji | ReactionEmoji;
|
export type EmojiResolvable = Snowflake | GuildEmoji | ReactionEmoji;
|
||||||
@@ -4646,7 +4714,11 @@ export interface MessageCollectorOptions extends CollectorOptions<[Message]> {
|
|||||||
maxProcessed?: number;
|
maxProcessed?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MessageComponent = Component | ActionRow<MessageActionRowComponent> | ButtonComponent | SelectMenuComponent;
|
export type MessageComponent =
|
||||||
|
| Component
|
||||||
|
| ActionRowBuilder<MessageActionRowComponentBuilder | ModalActionRowComponentBuilder>
|
||||||
|
| ButtonComponent
|
||||||
|
| SelectMenuComponent;
|
||||||
|
|
||||||
export type MessageComponentCollectorOptions<T extends MessageComponentInteraction> = Omit<
|
export type MessageComponentCollectorOptions<T extends MessageComponentInteraction> = Omit<
|
||||||
InteractionCollectorOptions<T>,
|
InteractionCollectorOptions<T>,
|
||||||
@@ -4666,6 +4738,7 @@ export interface MessageEditOptions {
|
|||||||
flags?: BitFieldResolvable<MessageFlagsString, number>;
|
flags?: BitFieldResolvable<MessageFlagsString, number>;
|
||||||
allowedMentions?: MessageMentionOptions;
|
allowedMentions?: MessageMentionOptions;
|
||||||
components?: (
|
components?: (
|
||||||
|
| JSONEncodable<APIActionRowComponent<APIMessageActionRowComponent>>
|
||||||
| ActionRow<MessageActionRowComponent>
|
| ActionRow<MessageActionRowComponent>
|
||||||
| (Required<BaseComponentData> & ActionRowData<MessageActionRowComponentData | MessageActionRowComponent>)
|
| (Required<BaseComponentData> & ActionRowData<MessageActionRowComponentData | MessageActionRowComponent>)
|
||||||
| APIActionRowComponent<APIMessageActionRowComponent>
|
| APIActionRowComponent<APIMessageActionRowComponent>
|
||||||
@@ -4705,8 +4778,9 @@ export interface MessageOptions {
|
|||||||
tts?: boolean;
|
tts?: boolean;
|
||||||
nonce?: string | number;
|
nonce?: string | number;
|
||||||
content?: string | null;
|
content?: string | null;
|
||||||
embeds?: (Embed | APIEmbed)[];
|
embeds?: (JSONEncodable<APIEmbed> | APIEmbed)[];
|
||||||
components?: (
|
components?: (
|
||||||
|
| JSONEncodable<APIActionRowComponent<APIMessageActionRowComponent>>
|
||||||
| ActionRow<MessageActionRowComponent>
|
| ActionRow<MessageActionRowComponent>
|
||||||
| (Required<BaseComponentData> & ActionRowData<MessageActionRowComponentData | MessageActionRowComponent>)
|
| (Required<BaseComponentData> & ActionRowData<MessageActionRowComponentData | MessageActionRowComponent>)
|
||||||
| APIActionRowComponent<APIMessageActionRowComponent>
|
| APIActionRowComponent<APIMessageActionRowComponent>
|
||||||
@@ -5255,6 +5329,8 @@ export {
|
|||||||
ApplicationCommandType,
|
ApplicationCommandType,
|
||||||
ApplicationCommandOptionType,
|
ApplicationCommandOptionType,
|
||||||
ApplicationCommandPermissionType,
|
ApplicationCommandPermissionType,
|
||||||
|
APIEmbedField,
|
||||||
|
APISelectMenuOption,
|
||||||
AuditLogEvent,
|
AuditLogEvent,
|
||||||
ButtonStyle,
|
ButtonStyle,
|
||||||
ChannelType,
|
ChannelType,
|
||||||
@@ -5290,12 +5366,13 @@ export {
|
|||||||
WebhookType,
|
WebhookType,
|
||||||
} from 'discord-api-types/v9';
|
} from 'discord-api-types/v9';
|
||||||
export {
|
export {
|
||||||
UnsafeButtonComponent,
|
UnsafeButtonBuilder,
|
||||||
UnsafeSelectMenuComponent,
|
UnsafeSelectMenuBuilder,
|
||||||
SelectMenuOption,
|
SelectMenuOptionBuilder,
|
||||||
UnsafeSelectMenuOption,
|
UnsafeSelectMenuOptionBuilder,
|
||||||
MessageActionRowComponent,
|
MessageActionRowComponentBuilder,
|
||||||
UnsafeEmbed,
|
ModalActionRowComponentBuilder,
|
||||||
ModalActionRowComponent,
|
UnsafeEmbedBuilder,
|
||||||
|
ModalBuilder,
|
||||||
} from '@discordjs/builders';
|
} from '@discordjs/builders';
|
||||||
export { DiscordAPIError, HTTPError, RateLimitError } from '@discordjs/rest';
|
export { DiscordAPIError, HTTPError, RateLimitError } from '@discordjs/rest';
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import {
|
|||||||
AuditLogEvent,
|
AuditLogEvent,
|
||||||
ButtonStyle,
|
ButtonStyle,
|
||||||
TextInputStyle,
|
TextInputStyle,
|
||||||
|
APITextInputComponent,
|
||||||
|
APIEmbed,
|
||||||
} from 'discord-api-types/v9';
|
} from 'discord-api-types/v9';
|
||||||
import {
|
import {
|
||||||
ApplicationCommand,
|
ApplicationCommand,
|
||||||
@@ -59,7 +61,7 @@ import {
|
|||||||
MessageCollector,
|
MessageCollector,
|
||||||
MessageComponentInteraction,
|
MessageComponentInteraction,
|
||||||
MessageReaction,
|
MessageReaction,
|
||||||
Modal,
|
ModalBuilder,
|
||||||
NewsChannel,
|
NewsChannel,
|
||||||
Options,
|
Options,
|
||||||
PartialTextBasedChannelFields,
|
PartialTextBasedChannelFields,
|
||||||
@@ -95,10 +97,10 @@ import {
|
|||||||
GuildAuditLogs,
|
GuildAuditLogs,
|
||||||
StageInstance,
|
StageInstance,
|
||||||
PartialDMChannel,
|
PartialDMChannel,
|
||||||
ActionRow,
|
ActionRowBuilder,
|
||||||
ButtonComponent,
|
ButtonComponent,
|
||||||
SelectMenuComponent,
|
SelectMenuComponent,
|
||||||
MessageActionRowComponent,
|
MessageActionRowComponentBuilder,
|
||||||
InteractionResponseFields,
|
InteractionResponseFields,
|
||||||
ThreadChannelType,
|
ThreadChannelType,
|
||||||
Events,
|
Events,
|
||||||
@@ -109,6 +111,12 @@ import {
|
|||||||
MessageActionRowComponentData,
|
MessageActionRowComponentData,
|
||||||
PartialThreadMember,
|
PartialThreadMember,
|
||||||
ThreadMemberFlagsBitField,
|
ThreadMemberFlagsBitField,
|
||||||
|
ButtonBuilder,
|
||||||
|
EmbedBuilder,
|
||||||
|
MessageActionRowComponent,
|
||||||
|
SelectMenuBuilder,
|
||||||
|
TextInputBuilder,
|
||||||
|
TextInputComponent,
|
||||||
Embed,
|
Embed,
|
||||||
} from '.';
|
} from '.';
|
||||||
import { expectAssignable, expectDeprecated, expectNotAssignable, expectNotType, expectType } from 'tsd';
|
import { expectAssignable, expectDeprecated, expectNotAssignable, expectNotType, expectType } from 'tsd';
|
||||||
@@ -574,7 +582,7 @@ client.on('messageCreate', async message => {
|
|||||||
assertIsMessage(channel.send({ embeds: [] }));
|
assertIsMessage(channel.send({ embeds: [] }));
|
||||||
|
|
||||||
const attachment = new MessageAttachment('file.png');
|
const attachment = new MessageAttachment('file.png');
|
||||||
const embed = new Embed();
|
const embed = new EmbedBuilder();
|
||||||
assertIsMessage(channel.send({ files: [attachment] }));
|
assertIsMessage(channel.send({ files: [attachment] }));
|
||||||
assertIsMessage(channel.send({ embeds: [embed] }));
|
assertIsMessage(channel.send({ embeds: [embed] }));
|
||||||
assertIsMessage(channel.send({ embeds: [embed], files: [attachment] }));
|
assertIsMessage(channel.send({ embeds: [embed], files: [attachment] }));
|
||||||
@@ -744,23 +752,24 @@ client.on('interactionCreate', async interaction => {
|
|||||||
|
|
||||||
if (!interaction.isCommand()) return;
|
if (!interaction.isCommand()) return;
|
||||||
|
|
||||||
void new ActionRow<MessageActionRowComponent>();
|
void new ActionRowBuilder<MessageActionRowComponentBuilder>();
|
||||||
|
|
||||||
const button = new ButtonComponent();
|
const button = new ButtonBuilder();
|
||||||
|
|
||||||
const actionRow = new ActionRow<MessageActionRowComponent>({
|
const actionRow = new ActionRowBuilder<MessageActionRowComponentBuilder>({
|
||||||
type: ComponentType.ActionRow,
|
type: ComponentType.ActionRow,
|
||||||
components: [button.toJSON()],
|
components: [button.toJSON()],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
actionRow.toJSON();
|
||||||
|
|
||||||
await interaction.reply({ content: 'Hi!', components: [actionRow] });
|
await interaction.reply({ content: 'Hi!', components: [actionRow] });
|
||||||
|
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
interaction.reply({ content: 'Hi!', components: [[button]] });
|
interaction.reply({ content: 'Hi!', components: [[button]] });
|
||||||
|
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
void new ActionRow({});
|
void new ActionRowBuilder({});
|
||||||
|
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
await interaction.reply({ content: 'Hi!', components: [button] });
|
await interaction.reply({ content: 'Hi!', components: [button] });
|
||||||
|
|
||||||
@@ -1336,34 +1345,34 @@ expectType<CategoryChannel | NewsChannel | StageChannel | StoreChannel | TextCha
|
|||||||
);
|
);
|
||||||
expectType<NewsChannel | TextChannel | ThreadChannel>(GuildTextBasedChannel);
|
expectType<NewsChannel | TextChannel | ThreadChannel>(GuildTextBasedChannel);
|
||||||
|
|
||||||
const button = new ButtonComponent({
|
const button = new ButtonBuilder({
|
||||||
label: 'test',
|
label: 'test',
|
||||||
style: ButtonStyle.Primary,
|
style: ButtonStyle.Primary,
|
||||||
customId: 'test',
|
customId: 'test',
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectMenu = new SelectMenuComponent({
|
const selectMenu = new SelectMenuBuilder({
|
||||||
maxValues: 10,
|
maxValues: 10,
|
||||||
minValues: 2,
|
minValues: 2,
|
||||||
customId: 'test',
|
customId: 'test',
|
||||||
});
|
});
|
||||||
|
|
||||||
new ActionRow({
|
new ActionRowBuilder({
|
||||||
components: [selectMenu.toJSON(), button.toJSON()],
|
components: [selectMenu.toJSON(), button.toJSON()],
|
||||||
});
|
});
|
||||||
|
|
||||||
new SelectMenuComponent({
|
new SelectMenuBuilder({
|
||||||
customId: 'foo',
|
customId: 'foo',
|
||||||
});
|
});
|
||||||
|
|
||||||
new ButtonComponent({
|
new ButtonBuilder({
|
||||||
style: ButtonStyle.Danger,
|
style: ButtonStyle.Danger,
|
||||||
});
|
});
|
||||||
|
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
new Embed().setColor('abc');
|
new EmbedBuilder().setColor('abc');
|
||||||
|
|
||||||
new Embed().setColor('#ffffff');
|
new EmbedBuilder().setColor('#ffffff');
|
||||||
|
|
||||||
expectNotAssignable<ActionRowData<MessageActionRowComponentData>>({
|
expectNotAssignable<ActionRowData<MessageActionRowComponentData>>({
|
||||||
type: ComponentType.ActionRow,
|
type: ComponentType.ActionRow,
|
||||||
@@ -1379,7 +1388,7 @@ declare const chatInputInteraction: ChatInputCommandInteraction;
|
|||||||
expectType<MessageAttachment>(chatInputInteraction.options.getAttachment('attachment', true));
|
expectType<MessageAttachment>(chatInputInteraction.options.getAttachment('attachment', true));
|
||||||
expectType<MessageAttachment | null>(chatInputInteraction.options.getAttachment('attachment'));
|
expectType<MessageAttachment | null>(chatInputInteraction.options.getAttachment('attachment'));
|
||||||
|
|
||||||
declare const modal: Modal;
|
declare const modal: ModalBuilder;
|
||||||
|
|
||||||
chatInputInteraction.showModal(modal);
|
chatInputInteraction.showModal(modal);
|
||||||
|
|
||||||
@@ -1400,3 +1409,27 @@ chatInputInteraction.showModal({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
declare const selectMenuData: APISelectMenuComponent;
|
||||||
|
SelectMenuBuilder.from(selectMenuData);
|
||||||
|
|
||||||
|
declare const selectMenuComp: SelectMenuComponent;
|
||||||
|
SelectMenuBuilder.from(selectMenuComp);
|
||||||
|
|
||||||
|
declare const buttonData: APIButtonComponent;
|
||||||
|
ButtonBuilder.from(buttonData);
|
||||||
|
|
||||||
|
declare const buttonComp: ButtonComponent;
|
||||||
|
ButtonBuilder.from(buttonComp);
|
||||||
|
|
||||||
|
declare const textInputData: APITextInputComponent;
|
||||||
|
TextInputBuilder.from(textInputData);
|
||||||
|
|
||||||
|
declare const textInputComp: TextInputComponent;
|
||||||
|
TextInputBuilder.from(textInputComp);
|
||||||
|
|
||||||
|
declare const embedData: APIEmbed;
|
||||||
|
EmbedBuilder.from(embedData);
|
||||||
|
|
||||||
|
declare const embedComp: Embed;
|
||||||
|
EmbedBuilder.from(embedComp);
|
||||||
|
|||||||
@@ -4446,6 +4446,7 @@ __metadata:
|
|||||||
eslint-config-prettier: ^8.3.0
|
eslint-config-prettier: ^8.3.0
|
||||||
eslint-plugin-import: ^2.25.4
|
eslint-plugin-import: ^2.25.4
|
||||||
eslint-plugin-prettier: ^4.0.0
|
eslint-plugin-prettier: ^4.0.0
|
||||||
|
fast-deep-equal: ^3.1.3
|
||||||
husky: ^7.0.4
|
husky: ^7.0.4
|
||||||
is-ci: ^3.0.1
|
is-ci: ^3.0.1
|
||||||
jest: ^27.5.1
|
jest: ^27.5.1
|
||||||
|
|||||||
Reference in New Issue
Block a user