mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-15 19:13:31 +01:00
refactor: make public builder props getters (#7422)
Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> Co-authored-by: Antonio Román <kyradiscord@gmail.com>
This commit is contained in:
@@ -5,7 +5,7 @@ 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 ActionRow().addComponents(new ButtonComponent())).not.toThrowError();
|
||||||
expect(() => new ActionRow().setComponents(new ButtonComponent())).not.toThrowError();
|
expect(() => new ActionRow().setComponents([new ButtonComponent()])).not.toThrowError();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN valid JSON input THEN valid JSON output is given', () => {
|
test('GIVEN valid JSON input THEN valid JSON output is given', () => {
|
||||||
@@ -84,10 +84,10 @@ describe('Action Row Components', () => {
|
|||||||
.setCustomId('1234')
|
.setCustomId('1234')
|
||||||
.setMaxValues(10)
|
.setMaxValues(10)
|
||||||
.setMinValues(12)
|
.setMinValues(12)
|
||||||
.setOptions(
|
.setOptions([
|
||||||
new SelectMenuOption().setLabel('one').setValue('one'),
|
new SelectMenuOption().setLabel('one').setValue('one'),
|
||||||
new SelectMenuOption().setLabel('two').setValue('two'),
|
new SelectMenuOption().setLabel('two').setValue('two'),
|
||||||
);
|
]);
|
||||||
|
|
||||||
expect(new ActionRow().addComponents(button).toJSON()).toEqual(rowWithButtonData);
|
expect(new ActionRow().addComponents(button).toJSON()).toEqual(rowWithButtonData);
|
||||||
expect(new ActionRow().addComponents(selectMenu).toJSON()).toEqual(rowWithSelectMenuData);
|
expect(new ActionRow().addComponents(selectMenu).toJSON()).toEqual(rowWithSelectMenuData);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ describe('Button 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();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN invalid inputs THEN Select Menu does throw', () => {
|
test('GIVEN invalid inputs THEN Select Menu does throw', () => {
|
||||||
@@ -55,17 +55,25 @@ describe('Button Components', () => {
|
|||||||
description: 'test',
|
description: 'test',
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectMenuData: APISelectMenuComponent = {
|
const selectMenuDataWithoutOptions = {
|
||||||
type: ComponentType.SelectMenu,
|
type: ComponentType.SelectMenu,
|
||||||
custom_id: 'test',
|
custom_id: 'test',
|
||||||
max_values: 10,
|
max_values: 10,
|
||||||
min_values: 3,
|
min_values: 3,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
options: [selectMenuOptionData],
|
|
||||||
placeholder: 'test',
|
placeholder: 'test',
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
const selectMenuData: APISelectMenuComponent = {
|
||||||
|
...selectMenuDataWithoutOptions,
|
||||||
|
options: [selectMenuOptionData],
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(new SelectMenuComponent(selectMenuData).toJSON()).toEqual(selectMenuData);
|
expect(
|
||||||
|
new SelectMenuComponent(selectMenuDataWithoutOptions)
|
||||||
|
.addOptions(new SelectMenuOption(selectMenuOptionData))
|
||||||
|
.toJSON(),
|
||||||
|
).toEqual(selectMenuData);
|
||||||
expect(new SelectMenuOption(selectMenuOptionData).toJSON()).toEqual(selectMenuOptionData);
|
expect(new SelectMenuOption(selectMenuOptionData).toJSON()).toEqual(selectMenuOptionData);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,19 +1,4 @@
|
|||||||
import { Embed } from '../../src';
|
import { Embed } from '../../src';
|
||||||
import type { APIEmbed } from 'discord-api-types/v9';
|
|
||||||
|
|
||||||
const emptyEmbed: APIEmbed = {
|
|
||||||
author: undefined,
|
|
||||||
color: undefined,
|
|
||||||
description: undefined,
|
|
||||||
fields: [],
|
|
||||||
footer: undefined,
|
|
||||||
image: undefined,
|
|
||||||
provider: undefined,
|
|
||||||
thumbnail: undefined,
|
|
||||||
title: undefined,
|
|
||||||
url: undefined,
|
|
||||||
video: undefined,
|
|
||||||
};
|
|
||||||
|
|
||||||
const alpha = 'abcdefghijklmnopqrstuvwxyz';
|
const alpha = 'abcdefghijklmnopqrstuvwxyz';
|
||||||
|
|
||||||
@@ -41,21 +26,21 @@ describe('Embed', () => {
|
|||||||
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 Embed({ title: 'foo' });
|
||||||
expect(embed.toJSON()).toStrictEqual({ ...emptyEmbed, 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 Embed();
|
||||||
embed.setTitle('foo');
|
embed.setTitle('foo');
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ ...emptyEmbed, 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 Embed({ title: 'foo' });
|
||||||
embed.setTitle(null);
|
embed.setTitle(null);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ ...emptyEmbed });
|
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', () => {
|
||||||
@@ -67,22 +52,22 @@ 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({ ...emptyEmbed, description: 'foo' });
|
const embed = new Embed({ description: 'foo' });
|
||||||
expect(embed.toJSON()).toStrictEqual({ ...emptyEmbed, 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 Embed();
|
||||||
embed.setDescription('foo');
|
embed.setDescription('foo');
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ ...emptyEmbed, 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 Embed({ description: 'foo' });
|
||||||
embed.setDescription(null);
|
embed.setDescription(null);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ ...emptyEmbed });
|
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', () => {
|
||||||
@@ -96,7 +81,6 @@ describe('Embed', () => {
|
|||||||
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 Embed({ url: 'https://discord.js.org/' });
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
...emptyEmbed,
|
|
||||||
url: 'https://discord.js.org/',
|
url: 'https://discord.js.org/',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -106,7 +90,6 @@ describe('Embed', () => {
|
|||||||
embed.setURL('https://discord.js.org/');
|
embed.setURL('https://discord.js.org/');
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
...emptyEmbed,
|
|
||||||
url: 'https://discord.js.org/',
|
url: 'https://discord.js.org/',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -115,7 +98,7 @@ describe('Embed', () => {
|
|||||||
const embed = new Embed({ url: 'https://discord.js.org' });
|
const embed = new Embed({ url: 'https://discord.js.org' });
|
||||||
embed.setURL(null);
|
embed.setURL(null);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ ...emptyEmbed });
|
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', () => {
|
||||||
@@ -128,21 +111,21 @@ 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 Embed({ color: 0xff0000 });
|
||||||
expect(embed.toJSON()).toStrictEqual({ ...emptyEmbed, 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', () => {
|
||||||
const embed = new Embed();
|
const embed = new Embed();
|
||||||
embed.setColor(0xff0000);
|
embed.setColor(0xff0000);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ ...emptyEmbed, color: 0xff0000 });
|
expect(embed.toJSON()).toStrictEqual({ color: 0xff0000 });
|
||||||
});
|
});
|
||||||
|
|
||||||
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 Embed({ color: 0xff0000 });
|
||||||
embed.setColor(null);
|
embed.setColor(null);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ ...emptyEmbed });
|
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', () => {
|
||||||
@@ -158,35 +141,35 @@ describe('Embed', () => {
|
|||||||
|
|
||||||
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 Embed({ timestamp: now.toISOString() });
|
||||||
expect(embed.toJSON()).toStrictEqual({ ...emptyEmbed, 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 Embed();
|
||||||
embed.setTimestamp(now);
|
embed.setTimestamp(now);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ ...emptyEmbed, 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 Embed();
|
||||||
embed.setTimestamp(now.getTime());
|
embed.setTimestamp(now.getTime());
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ ...emptyEmbed, 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 Embed();
|
||||||
embed.setTimestamp();
|
embed.setTimestamp();
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ ...emptyEmbed, timestamp: embed.timestamp });
|
expect(embed.toJSON()).toStrictEqual({ timestamp: embed.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 Embed({ timestamp: now.toISOString() });
|
||||||
embed.setTimestamp(null);
|
embed.setTimestamp(null);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ ...emptyEmbed, timestamp: undefined });
|
expect(embed.toJSON()).toStrictEqual({ timestamp: undefined });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -194,7 +177,6 @@ describe('Embed', () => {
|
|||||||
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 Embed({ thumbnail: { url: 'https://discord.js.org/static/logo.svg' } });
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
...emptyEmbed,
|
|
||||||
thumbnail: { url: 'https://discord.js.org/static/logo.svg' },
|
thumbnail: { url: 'https://discord.js.org/static/logo.svg' },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -204,7 +186,6 @@ describe('Embed', () => {
|
|||||||
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({
|
||||||
...emptyEmbed,
|
|
||||||
thumbnail: { url: 'https://discord.js.org/static/logo.svg' },
|
thumbnail: { url: 'https://discord.js.org/static/logo.svg' },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -213,7 +194,7 @@ describe('Embed', () => {
|
|||||||
const embed = new Embed({ thumbnail: { url: 'https://discord.js.org/static/logo.svg' } });
|
const embed = new Embed({ thumbnail: { url: 'https://discord.js.org/static/logo.svg' } });
|
||||||
embed.setThumbnail(null);
|
embed.setThumbnail(null);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ ...emptyEmbed });
|
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', () => {
|
||||||
@@ -227,7 +208,6 @@ describe('Embed', () => {
|
|||||||
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 Embed({ image: { url: 'https://discord.js.org/static/logo.svg' } });
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
...emptyEmbed,
|
|
||||||
image: { url: 'https://discord.js.org/static/logo.svg' },
|
image: { url: 'https://discord.js.org/static/logo.svg' },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -237,7 +217,6 @@ describe('Embed', () => {
|
|||||||
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({
|
||||||
...emptyEmbed,
|
|
||||||
image: { url: 'https://discord.js.org/static/logo.svg' },
|
image: { url: 'https://discord.js.org/static/logo.svg' },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -246,7 +225,7 @@ describe('Embed', () => {
|
|||||||
const embed = new Embed({ image: { url: 'https://discord.js/org/static/logo.svg' } });
|
const embed = new Embed({ image: { url: 'https://discord.js/org/static/logo.svg' } });
|
||||||
embed.setImage(null);
|
embed.setImage(null);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ ...emptyEmbed });
|
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', () => {
|
||||||
@@ -262,7 +241,6 @@ describe('Embed', () => {
|
|||||||
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({
|
||||||
...emptyEmbed,
|
|
||||||
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' },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -276,7 +254,6 @@ describe('Embed', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
...emptyEmbed,
|
|
||||||
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' },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -287,7 +264,7 @@ describe('Embed', () => {
|
|||||||
});
|
});
|
||||||
embed.setAuthor(null);
|
embed.setAuthor(null);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ ...emptyEmbed });
|
expect(embed.toJSON()).toStrictEqual({ author: undefined });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with an invalid author name THEN throws error', () => {
|
test('GIVEN an embed with an invalid author name THEN throws error', () => {
|
||||||
@@ -303,7 +280,6 @@ describe('Embed', () => {
|
|||||||
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({
|
||||||
...emptyEmbed,
|
|
||||||
footer: { text: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg' },
|
footer: { text: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg' },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -313,7 +289,6 @@ describe('Embed', () => {
|
|||||||
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({
|
||||||
...emptyEmbed,
|
|
||||||
footer: { text: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg' },
|
footer: { text: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg' },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -322,7 +297,7 @@ describe('Embed', () => {
|
|||||||
const embed = new Embed({ footer: { text: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg' } });
|
const embed = new Embed({ footer: { text: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg' } });
|
||||||
embed.setFooter(null);
|
embed.setFooter(null);
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({ ...emptyEmbed });
|
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', () => {
|
||||||
@@ -338,7 +313,6 @@ describe('Embed', () => {
|
|||||||
fields: [{ name: 'foo', value: 'bar', inline: undefined }],
|
fields: [{ name: 'foo', value: 'bar', inline: undefined }],
|
||||||
});
|
});
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
...emptyEmbed,
|
|
||||||
fields: [{ name: 'foo', value: 'bar', inline: undefined }],
|
fields: [{ name: 'foo', value: 'bar', inline: undefined }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -348,7 +322,6 @@ describe('Embed', () => {
|
|||||||
embed.addField({ name: 'foo', value: 'bar' });
|
embed.addField({ name: 'foo', value: 'bar' });
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
...emptyEmbed,
|
|
||||||
fields: [{ name: 'foo', value: 'bar', inline: undefined }],
|
fields: [{ name: 'foo', value: 'bar', inline: undefined }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -358,7 +331,6 @@ describe('Embed', () => {
|
|||||||
embed.addFields({ name: 'foo', value: 'bar' });
|
embed.addFields({ name: 'foo', value: 'bar' });
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
...emptyEmbed,
|
|
||||||
fields: [{ name: 'foo', value: 'bar', inline: undefined }],
|
fields: [{ name: 'foo', value: 'bar', inline: undefined }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -368,7 +340,6 @@ describe('Embed', () => {
|
|||||||
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({
|
||||||
...emptyEmbed,
|
|
||||||
fields: [{ name: 'foo', value: 'baz', inline: undefined }],
|
fields: [{ name: 'foo', value: 'baz', inline: undefined }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { APIActionRowComponent, ComponentType } from 'discord-api-types/v9';
|
import { type APIActionRowComponent, ComponentType } from 'discord-api-types/v9';
|
||||||
import type { ButtonComponent, SelectMenuComponent } from '..';
|
import type { ButtonComponent, SelectMenuComponent } from '..';
|
||||||
import type { Component } from './Component';
|
import { Component } from './Component';
|
||||||
import { createComponent } from './Components';
|
import { createComponent } from './Components';
|
||||||
|
|
||||||
export type MessageComponent = ActionRowComponent | ActionRow;
|
export type MessageComponent = ActionRowComponent | ActionRow;
|
||||||
@@ -8,16 +8,17 @@ export type MessageComponent = ActionRowComponent | ActionRow;
|
|||||||
export type ActionRowComponent = ButtonComponent | SelectMenuComponent;
|
export type ActionRowComponent = ButtonComponent | SelectMenuComponent;
|
||||||
|
|
||||||
// TODO: Add valid form component types
|
// TODO: Add valid form component types
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an action row component
|
* Represents an action row component
|
||||||
*/
|
*/
|
||||||
export class ActionRow<T extends ActionRowComponent = ActionRowComponent> implements Component {
|
export class ActionRow<T extends ActionRowComponent = ActionRowComponent> extends Component<
|
||||||
public readonly components: T[] = [];
|
Omit<Partial<APIActionRowComponent> & { type: ComponentType.ActionRow }, 'components'>
|
||||||
public readonly type = ComponentType.ActionRow;
|
> {
|
||||||
|
public readonly components: T[];
|
||||||
|
|
||||||
public constructor(data?: APIActionRowComponent & { type?: ComponentType.ActionRow }) {
|
public constructor({ components, ...data }: Partial<APIActionRowComponent> = {}) {
|
||||||
this.components = (data?.components.map(createComponent) ?? []) as T[];
|
super({ type: ComponentType.ActionRow, ...data });
|
||||||
|
this.components = (components?.map((c) => createComponent(c)) ?? []) as T[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,14 +35,14 @@ export class ActionRow<T extends ActionRowComponent = ActionRowComponent> implem
|
|||||||
* Sets the components in this action row
|
* Sets the components in this action row
|
||||||
* @param components The components to set this row to
|
* @param components The components to set this row to
|
||||||
*/
|
*/
|
||||||
public setComponents(...components: T[]) {
|
public setComponents(components: T[]) {
|
||||||
Reflect.set(this, 'components', [...components]);
|
this.components.splice(0, this.components.length, ...components);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public toJSON(): APIActionRowComponent {
|
public toJSON(): APIActionRowComponent {
|
||||||
return {
|
return {
|
||||||
...this,
|
...this.data,
|
||||||
components: this.components.map((component) => component.toJSON()),
|
components: this.components.map((component) => component.toJSON()),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export function validateRequiredSelectMenuOptionParameters(label?: string, value
|
|||||||
export const urlValidator = z.string().url();
|
export const urlValidator = z.string().url();
|
||||||
|
|
||||||
export function validateRequiredButtonParameters(
|
export function validateRequiredButtonParameters(
|
||||||
style: ButtonStyle,
|
style?: ButtonStyle,
|
||||||
label?: string,
|
label?: string,
|
||||||
emoji?: APIMessageComponentEmoji,
|
emoji?: APIMessageComponentEmoji,
|
||||||
customId?: string,
|
customId?: string,
|
||||||
|
|||||||
@@ -1,12 +1,33 @@
|
|||||||
import type { APIMessageComponent, ComponentType } from 'discord-api-types/v9';
|
|
||||||
import type { JSONEncodable } from '../util/jsonEncodable';
|
import type { JSONEncodable } from '../util/jsonEncodable';
|
||||||
|
import type { APIBaseMessageComponent, APIMessageComponent, ComponentType } from 'discord-api-types/v9';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a discord component
|
* Represents a discord component
|
||||||
*/
|
*/
|
||||||
export interface Component extends JSONEncodable<APIMessageComponent> {
|
export abstract class Component<
|
||||||
|
DataType extends Partial<APIBaseMessageComponent<ComponentType>> & {
|
||||||
|
type: ComponentType;
|
||||||
|
} = APIBaseMessageComponent<ComponentType>,
|
||||||
|
> implements JSONEncodable<APIMessageComponent>
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The API data associated with this component
|
||||||
|
*/
|
||||||
|
protected readonly data: DataType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts this component to an API-compatible JSON object
|
||||||
|
*/
|
||||||
|
public abstract toJSON(): APIMessageComponent;
|
||||||
|
|
||||||
|
public constructor(data: DataType) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of this component
|
* The type of this component
|
||||||
*/
|
*/
|
||||||
readonly type: ComponentType;
|
public get type(): DataType['type'] {
|
||||||
|
return this.data.type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ export function createComponent<C extends MessageComponent>(data: C): C;
|
|||||||
export function createComponent(data: APIMessageComponent | MessageComponent): Component {
|
export function createComponent(data: APIMessageComponent | MessageComponent): Component {
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
case ComponentType.ActionRow:
|
case ComponentType.ActionRow:
|
||||||
return data instanceof ActionRow ? data : new ActionRow(data);
|
return (data instanceof ActionRow ? data : new ActionRow(data)) as Component;
|
||||||
case ComponentType.Button:
|
case ComponentType.Button:
|
||||||
return data instanceof ButtonComponent ? data : new ButtonComponent(data);
|
return (data instanceof ButtonComponent ? data : new ButtonComponent(data)) as Component;
|
||||||
case ComponentType.SelectMenu:
|
case ComponentType.SelectMenu:
|
||||||
return data instanceof SelectMenuComponent ? data : new SelectMenuComponent(data);
|
return (data instanceof SelectMenuComponent ? data : new SelectMenuComponent(data)) as Component;
|
||||||
default:
|
default:
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
throw new Error(`Cannot serialize component type: ${data.type as number}`);
|
throw new Error(`Cannot serialize component type: ${data.type as number}`);
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ import {
|
|||||||
} from '../Assertions';
|
} from '../Assertions';
|
||||||
import { UnsafeButtonComponent } from './UnsafeButton';
|
import { UnsafeButtonComponent } from './UnsafeButton';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a validated button component
|
||||||
|
*/
|
||||||
export class ButtonComponent extends UnsafeButtonComponent {
|
export class ButtonComponent extends UnsafeButtonComponent {
|
||||||
public override setStyle(style: ButtonStyle) {
|
public override setStyle(style: ButtonStyle) {
|
||||||
return super.setStyle(buttonStyleValidator.parse(style));
|
return super.setStyle(buttonStyleValidator.parse(style));
|
||||||
@@ -36,7 +39,7 @@ export class ButtonComponent extends UnsafeButtonComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override toJSON(): APIButtonComponent {
|
public override toJSON(): APIButtonComponent {
|
||||||
validateRequiredButtonParameters(this.style, this.label, this.emoji, this.custom_id, this.url);
|
validateRequiredButtonParameters(this.style, this.label, this.emoji, this.customId, this.url);
|
||||||
return super.toJSON();
|
return super.toJSON();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,33 +3,59 @@ import {
|
|||||||
ButtonStyle,
|
ButtonStyle,
|
||||||
type APIMessageComponentEmoji,
|
type APIMessageComponentEmoji,
|
||||||
type APIButtonComponent,
|
type APIButtonComponent,
|
||||||
|
type APIButtonComponentWithURL,
|
||||||
|
type APIButtonComponentWithCustomId,
|
||||||
} from 'discord-api-types/v9';
|
} from 'discord-api-types/v9';
|
||||||
import type { Component } from '../Component';
|
import { Component } from '../Component';
|
||||||
|
|
||||||
export class UnsafeButtonComponent implements Component {
|
/**
|
||||||
public readonly type = ComponentType.Button as const;
|
* Represents a non-validated button component
|
||||||
public readonly style!: ButtonStyle;
|
*/
|
||||||
public readonly label?: string;
|
export class UnsafeButtonComponent extends Component<Partial<APIButtonComponent> & { type: ComponentType.Button }> {
|
||||||
public readonly emoji?: APIMessageComponentEmoji;
|
public constructor(data?: Partial<APIButtonComponent>) {
|
||||||
public readonly disabled?: boolean;
|
super({ type: ComponentType.Button, ...data });
|
||||||
public readonly custom_id!: string;
|
}
|
||||||
public readonly url!: string;
|
|
||||||
|
|
||||||
public constructor(data?: APIButtonComponent & { type?: ComponentType.Button }) {
|
/**
|
||||||
/* eslint-disable @typescript-eslint/non-nullable-type-assertion-style */
|
* The style of this button
|
||||||
this.style = data?.style as ButtonStyle;
|
*/
|
||||||
this.label = data?.label;
|
public get style() {
|
||||||
this.emoji = data?.emoji;
|
return this.data.style;
|
||||||
this.disabled = data?.disabled;
|
}
|
||||||
|
|
||||||
// This if/else makes typescript happy
|
/**
|
||||||
if (data?.style === ButtonStyle.Link) {
|
* The label of this button
|
||||||
this.url = data.url;
|
*/
|
||||||
} else {
|
public get label() {
|
||||||
this.custom_id = data?.custom_id as string;
|
return this.data.label;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-enable @typescript-eslint/non-nullable-type-assertion-style */
|
/**
|
||||||
|
* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,7 +63,7 @@ export class UnsafeButtonComponent implements Component {
|
|||||||
* @param style The style of the button
|
* @param style The style of the button
|
||||||
*/
|
*/
|
||||||
public setStyle(style: ButtonStyle) {
|
public setStyle(style: ButtonStyle) {
|
||||||
Reflect.set(this, 'style', style);
|
this.data.style = style;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,16 +72,16 @@ export class UnsafeButtonComponent implements Component {
|
|||||||
* @param url The URL to open when this button is clicked
|
* @param url The URL to open when this button is clicked
|
||||||
*/
|
*/
|
||||||
public setURL(url: string) {
|
public setURL(url: string) {
|
||||||
Reflect.set(this, 'url', url);
|
(this.data as APIButtonComponentWithURL).url = url;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the custom Id for this button
|
* Sets the custom Id for this button
|
||||||
* @param customId The custom ID to use for this button
|
* @param customId The custom id to use for this button
|
||||||
*/
|
*/
|
||||||
public setCustomId(customId: string) {
|
public setCustomId(customId: string) {
|
||||||
Reflect.set(this, 'custom_id', customId);
|
(this.data as APIButtonComponentWithCustomId).custom_id = customId;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +90,7 @@ export class UnsafeButtonComponent implements Component {
|
|||||||
* @param emoji The emoji to display on this button
|
* @param emoji The emoji to display on this button
|
||||||
*/
|
*/
|
||||||
public setEmoji(emoji: APIMessageComponentEmoji) {
|
public setEmoji(emoji: APIMessageComponentEmoji) {
|
||||||
Reflect.set(this, 'emoji', emoji);
|
this.data.emoji = emoji;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +99,7 @@ export class UnsafeButtonComponent implements Component {
|
|||||||
* @param disabled Whether or not to disable this button or not
|
* @param disabled Whether or not to disable this button or not
|
||||||
*/
|
*/
|
||||||
public setDisabled(disabled: boolean) {
|
public setDisabled(disabled: boolean) {
|
||||||
Reflect.set(this, 'disabled', disabled);
|
this.data.disabled = disabled;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,13 +108,14 @@ export class UnsafeButtonComponent implements Component {
|
|||||||
* @param label The label to display on this button
|
* @param label The label to display on this button
|
||||||
*/
|
*/
|
||||||
public setLabel(label: string) {
|
public setLabel(label: string) {
|
||||||
Reflect.set(this, 'label', label);
|
this.data.label = label;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public toJSON(): APIButtonComponent {
|
public toJSON(): APIButtonComponent {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
return {
|
return {
|
||||||
...this,
|
...this.data,
|
||||||
};
|
} as APIButtonComponent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
import { UnsafeSelectMenuComponent } from './UnsafeSelectMenu';
|
import { UnsafeSelectMenuComponent } from './UnsafeSelectMenu';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a select menu component
|
* Represents a validated select menu component
|
||||||
*/
|
*/
|
||||||
export class SelectMenuComponent extends UnsafeSelectMenuComponent {
|
export class SelectMenuComponent extends UnsafeSelectMenuComponent {
|
||||||
public override setPlaceholder(placeholder: string) {
|
public override setPlaceholder(placeholder: string) {
|
||||||
@@ -33,7 +33,7 @@ export class SelectMenuComponent extends UnsafeSelectMenuComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override toJSON(): APISelectMenuComponent {
|
public override toJSON(): APISelectMenuComponent {
|
||||||
validateRequiredSelectMenuParameters(this.options, this.custom_id);
|
validateRequiredSelectMenuParameters(this.options, this.customId);
|
||||||
return super.toJSON();
|
return super.toJSON();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
import { UnsafeSelectMenuOption } from './UnsafeSelectMenuOption';
|
import { UnsafeSelectMenuOption } from './UnsafeSelectMenuOption';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an option within a select menu component
|
* Represents a validated option within a select menu component
|
||||||
*/
|
*/
|
||||||
export class SelectMenuOption extends UnsafeSelectMenuOption {
|
export class SelectMenuOption extends UnsafeSelectMenuOption {
|
||||||
public override setDescription(description: string) {
|
public override setDescription(description: string) {
|
||||||
|
|||||||
@@ -1,28 +1,54 @@
|
|||||||
import { ComponentType, type APISelectMenuComponent } from 'discord-api-types/v9';
|
import { ComponentType, type APISelectMenuComponent } from 'discord-api-types/v9';
|
||||||
import type { Component } from '../Component';
|
import { Component } from '../Component';
|
||||||
import { SelectMenuOption } from './SelectMenuOption';
|
import { UnsafeSelectMenuOption } from './UnsafeSelectMenuOption';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a non-validated select menu component
|
* Represents a non-validated select menu component
|
||||||
*/
|
*/
|
||||||
export class UnsafeSelectMenuComponent implements Component {
|
export class UnsafeSelectMenuComponent extends Component<
|
||||||
public readonly type = ComponentType.SelectMenu as const;
|
Partial<Omit<APISelectMenuComponent, 'options'>> & { type: ComponentType.SelectMenu }
|
||||||
public readonly options: SelectMenuOption[];
|
> {
|
||||||
public readonly placeholder?: string;
|
public readonly options: UnsafeSelectMenuOption[];
|
||||||
public readonly min_values?: number;
|
|
||||||
public readonly max_values?: number;
|
|
||||||
public readonly custom_id!: string;
|
|
||||||
public readonly disabled?: boolean;
|
|
||||||
|
|
||||||
public constructor(data?: APISelectMenuComponent) {
|
public constructor(data?: Partial<APISelectMenuComponent>) {
|
||||||
this.options = data?.options.map((option) => new SelectMenuOption(option)) ?? [];
|
const { options, ...initData } = data ?? {};
|
||||||
this.placeholder = data?.placeholder;
|
super({ type: ComponentType.SelectMenu, ...initData });
|
||||||
this.min_values = data?.min_values;
|
this.options = options?.map((o) => new UnsafeSelectMenuOption(o)) ?? [];
|
||||||
this.max_values = data?.max_values;
|
}
|
||||||
/* eslint-disable @typescript-eslint/non-nullable-type-assertion-style */
|
|
||||||
this.custom_id = data?.custom_id as string;
|
/**
|
||||||
/* eslint-enable @typescript-eslint/non-nullable-type-assertion-style */
|
* The placeholder for this select menu
|
||||||
this.disabled = data?.disabled;
|
*/
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,34 +56,34 @@ export class UnsafeSelectMenuComponent implements Component {
|
|||||||
* @param placeholder The placeholder to use for this select menu
|
* @param placeholder The placeholder to use for this select menu
|
||||||
*/
|
*/
|
||||||
public setPlaceholder(placeholder: string) {
|
public setPlaceholder(placeholder: string) {
|
||||||
Reflect.set(this, 'placeholder', placeholder);
|
this.data.placeholder = placeholder;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets thes minimum values that must be selected in the select menu
|
* Sets the minimum values that must be selected in the select menu
|
||||||
* @param minValues The minimum values that must be selected
|
* @param minValues The minimum values that must be selected
|
||||||
*/
|
*/
|
||||||
public setMinValues(minValues: number) {
|
public setMinValues(minValues: number) {
|
||||||
Reflect.set(this, 'min_values', minValues);
|
this.data.min_values = minValues;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets thes maximum values that must be selected in the select menu
|
* Sets the maximum values that must be selected in the select menu
|
||||||
* @param minValues The maximum values that must be selected
|
* @param minValues The maximum values that must be selected
|
||||||
*/
|
*/
|
||||||
public setMaxValues(maxValues: number) {
|
public setMaxValues(maxValues: number) {
|
||||||
Reflect.set(this, 'max_values', maxValues);
|
this.data.max_values = maxValues;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the custom Id for this select menu
|
* Sets the custom Id for this select menu
|
||||||
* @param customId The custom ID to use for this select menu
|
* @param customId The custom id to use for this select menu
|
||||||
*/
|
*/
|
||||||
public setCustomId(customId: string) {
|
public setCustomId(customId: string) {
|
||||||
Reflect.set(this, 'custom_id', customId);
|
this.data.custom_id = customId;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +92,7 @@ export class UnsafeSelectMenuComponent implements Component {
|
|||||||
* @param disabled Whether or not this select menu is disabled
|
* @param disabled Whether or not this select menu is disabled
|
||||||
*/
|
*/
|
||||||
public setDisabled(disabled: boolean) {
|
public setDisabled(disabled: boolean) {
|
||||||
Reflect.set(this, 'disabled', disabled);
|
this.data.disabled = disabled;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +101,7 @@ export class UnsafeSelectMenuComponent implements 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: SelectMenuOption[]) {
|
public addOptions(...options: UnsafeSelectMenuOption[]) {
|
||||||
this.options.push(...options);
|
this.options.push(...options);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -84,15 +110,16 @@ export class UnsafeSelectMenuComponent implements 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: SelectMenuOption[]) {
|
public setOptions(options: UnsafeSelectMenuOption[]) {
|
||||||
Reflect.set(this, 'options', [...options]);
|
this.options.splice(0, this.options.length, ...options);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public toJSON(): APISelectMenuComponent {
|
public toJSON(): APISelectMenuComponent {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
return {
|
return {
|
||||||
...this,
|
...this.data,
|
||||||
options: this.options.map((option) => option.toJSON()),
|
options: this.options.map((o) => o.toJSON()),
|
||||||
};
|
} as APISelectMenuComponent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,20 +4,41 @@ 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 UnsafeSelectMenuOption {
|
||||||
public readonly label!: string;
|
public constructor(protected data: Partial<APISelectMenuOption> = {}) {}
|
||||||
public readonly value!: string;
|
|
||||||
public readonly description?: string;
|
|
||||||
public readonly emoji?: APIMessageComponentEmoji;
|
|
||||||
public readonly default?: boolean;
|
|
||||||
|
|
||||||
public constructor(data?: APISelectMenuOption) {
|
/**
|
||||||
/* eslint-disable @typescript-eslint/non-nullable-type-assertion-style */
|
* The label for this option
|
||||||
this.label = data?.label as string;
|
*/
|
||||||
this.value = data?.value as string;
|
public get label() {
|
||||||
/* eslint-enable @typescript-eslint/non-nullable-type-assertion-style */
|
return this.data.label;
|
||||||
this.description = data?.description;
|
}
|
||||||
this.emoji = data?.emoji;
|
|
||||||
this.default = data?.default;
|
/**
|
||||||
|
* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,7 +46,7 @@ export class UnsafeSelectMenuOption {
|
|||||||
* @param label The label to show on this option
|
* @param label The label to show on this option
|
||||||
*/
|
*/
|
||||||
public setLabel(label: string) {
|
public setLabel(label: string) {
|
||||||
Reflect.set(this, 'label', label);
|
this.data.label = label;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,7 +55,7 @@ export class UnsafeSelectMenuOption {
|
|||||||
* @param value The value of this option
|
* @param value The value of this option
|
||||||
*/
|
*/
|
||||||
public setValue(value: string) {
|
public setValue(value: string) {
|
||||||
Reflect.set(this, 'value', value);
|
this.data.value = value;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,16 +64,16 @@ export class UnsafeSelectMenuOption {
|
|||||||
* @param description The description of this option
|
* @param description The description of this option
|
||||||
*/
|
*/
|
||||||
public setDescription(description: string) {
|
public setDescription(description: string) {
|
||||||
Reflect.set(this, 'description', description);
|
this.data.description = description;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether this option is selected by default
|
* Sets whether this option is selected by default
|
||||||
* @param isDefault Whether or not this option is selected by default
|
* @param isDefault Whether this option is selected by default
|
||||||
*/
|
*/
|
||||||
public setDefault(isDefault: boolean) {
|
public setDefault(isDefault: boolean) {
|
||||||
Reflect.set(this, 'default', isDefault);
|
this.data.default = isDefault;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,13 +82,14 @@ export class UnsafeSelectMenuOption {
|
|||||||
* @param emoji The emoji to display on this button
|
* @param emoji The emoji to display on this button
|
||||||
*/
|
*/
|
||||||
public setEmoji(emoji: APIMessageComponentEmoji) {
|
public setEmoji(emoji: APIMessageComponentEmoji) {
|
||||||
Reflect.set(this, 'emoji', emoji);
|
this.data.emoji = emoji;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public toJSON(): APISelectMenuOption {
|
public toJSON(): APISelectMenuOption {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
return {
|
return {
|
||||||
...this,
|
...this.data,
|
||||||
};
|
} as APISelectMenuOption;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ export const embedFieldsArrayPredicate = embedFieldPredicate.array();
|
|||||||
|
|
||||||
export const fieldLengthPredicate = z.number().lte(25);
|
export const fieldLengthPredicate = z.number().lte(25);
|
||||||
|
|
||||||
export function validateFieldLength(fields: APIEmbedField[], amountAdding: number): void {
|
export function validateFieldLength(amountAdding: number, fields?: APIEmbedField[]): void {
|
||||||
fieldLengthPredicate.parse(fields.length + amountAdding);
|
fieldLengthPredicate.parse((fields?.length ?? 0) + amountAdding);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const authorNamePredicate = fieldNamePredicate.nullable();
|
export const authorNamePredicate = fieldNamePredicate.nullable();
|
||||||
|
|||||||
@@ -13,15 +13,15 @@ import {
|
|||||||
urlPredicate,
|
urlPredicate,
|
||||||
validateFieldLength,
|
validateFieldLength,
|
||||||
} from './Assertions';
|
} from './Assertions';
|
||||||
import { AuthorOptions, FooterOptions, UnsafeEmbed } from './UnsafeEmbed';
|
import { EmbedAuthorOptions, EmbedFooterOptions, UnsafeEmbed } from './UnsafeEmbed';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an 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 Embed extends UnsafeEmbed {
|
||||||
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(this.fields, fields.length);
|
validateFieldLength(fields.length, this.fields);
|
||||||
|
|
||||||
// Data assertions
|
// Data assertions
|
||||||
return super.addFields(...embedFieldsArrayPredicate.parse(fields));
|
return super.addFields(...embedFieldsArrayPredicate.parse(fields));
|
||||||
@@ -29,13 +29,13 @@ 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(this.fields, fields.length - deleteCount);
|
validateFieldLength(fields.length - deleteCount, this.fields);
|
||||||
|
|
||||||
// Data assertions
|
// Data assertions
|
||||||
return super.spliceFields(index, deleteCount, ...embedFieldsArrayPredicate.parse(fields));
|
return super.spliceFields(index, deleteCount, ...embedFieldsArrayPredicate.parse(fields));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override setAuthor(options: AuthorOptions | null): this {
|
public override setAuthor(options: EmbedAuthorOptions | null): this {
|
||||||
if (options === null) {
|
if (options === null) {
|
||||||
return super.setAuthor(null);
|
return super.setAuthor(null);
|
||||||
}
|
}
|
||||||
@@ -58,7 +58,7 @@ export class Embed extends UnsafeEmbed {
|
|||||||
return super.setDescription(descriptionPredicate.parse(description));
|
return super.setDescription(descriptionPredicate.parse(description));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override setFooter(options: FooterOptions | null): this {
|
public override setFooter(options: EmbedFooterOptions | null): this {
|
||||||
if (options === null) {
|
if (options === null) {
|
||||||
return super.setFooter(null);
|
return super.setFooter(null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,98 +4,151 @@ import type {
|
|||||||
APIEmbedField,
|
APIEmbedField,
|
||||||
APIEmbedFooter,
|
APIEmbedFooter,
|
||||||
APIEmbedImage,
|
APIEmbedImage,
|
||||||
APIEmbedProvider,
|
|
||||||
APIEmbedThumbnail,
|
|
||||||
APIEmbedVideo,
|
APIEmbedVideo,
|
||||||
} from 'discord-api-types/v9';
|
} from 'discord-api-types/v9';
|
||||||
import type { JSONEncodable } from '../../util/jsonEncodable';
|
|
||||||
|
|
||||||
export interface AuthorOptions {
|
export interface IconData {
|
||||||
name: string;
|
/**
|
||||||
url?: string;
|
* The URL of the icon
|
||||||
|
*/
|
||||||
iconURL?: string;
|
iconURL?: string;
|
||||||
|
/**
|
||||||
|
* The proxy URL of the icon
|
||||||
|
*/
|
||||||
|
proxyIconURL?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FooterOptions {
|
export type EmbedAuthorData = Omit<APIEmbedAuthor, 'icon_url' | 'proxy_icon_url'> & IconData;
|
||||||
text: string;
|
|
||||||
iconURL?: string;
|
export type EmbedAuthorOptions = Omit<EmbedAuthorData, 'proxyIconURL'>;
|
||||||
|
|
||||||
|
export type EmbedFooterData = Omit<APIEmbedFooter, 'icon_url' | 'proxy_icon_url'> & IconData;
|
||||||
|
|
||||||
|
export type EmbedFooterOptions = Omit<EmbedFooterData, 'proxyIconURL'>;
|
||||||
|
|
||||||
|
export interface EmbedImageData extends Omit<APIEmbedImage, 'proxy_url'> {
|
||||||
|
/**
|
||||||
|
* The proxy URL for the image
|
||||||
|
*/
|
||||||
|
proxyURL?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UnsafeEmbed implements APIEmbed, JSONEncodable<APIEmbed> {
|
/**
|
||||||
|
* Represents a non-validated embed in a message (image/video preview, rich embed, etc.)
|
||||||
|
*/
|
||||||
|
export class UnsafeEmbed {
|
||||||
|
protected data: APIEmbed;
|
||||||
|
|
||||||
|
public constructor(data: APIEmbed = {}) {
|
||||||
|
this.data = { ...data };
|
||||||
|
if (data.timestamp) this.data.timestamp = new Date(data.timestamp).toISOString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of fields of this embed
|
* An array of fields of this embed
|
||||||
*/
|
*/
|
||||||
public readonly fields: APIEmbedField[];
|
public get fields() {
|
||||||
|
return this.data.fields;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The embed title
|
* The embed title
|
||||||
*/
|
*/
|
||||||
public readonly title?: string;
|
public get title() {
|
||||||
|
return this.data.title;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The embed description
|
* The embed description
|
||||||
*/
|
*/
|
||||||
public readonly description?: string;
|
public get description() {
|
||||||
|
return this.data.description;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The embed url
|
* The embed URL
|
||||||
*/
|
*/
|
||||||
public readonly url?: string;
|
public get url() {
|
||||||
|
return this.data.url;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The embed color
|
* The embed color
|
||||||
*/
|
*/
|
||||||
public readonly color?: number;
|
public get color() {
|
||||||
|
return this.data.color;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The timestamp of the embed in the ISO format
|
* The timestamp of the embed in an ISO 8601 format
|
||||||
*/
|
*/
|
||||||
public readonly timestamp?: string;
|
public get timestamp() {
|
||||||
|
return this.data.timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The embed thumbnail data
|
* The embed thumbnail data
|
||||||
*/
|
*/
|
||||||
public readonly thumbnail?: APIEmbedThumbnail;
|
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
|
* The embed image data
|
||||||
*/
|
*/
|
||||||
public readonly image?: APIEmbedImage;
|
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
|
* Received video data
|
||||||
*/
|
*/
|
||||||
public readonly video?: APIEmbedVideo;
|
public get video(): APIEmbedVideo | undefined {
|
||||||
|
return this.data.video;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The embed author data
|
* The embed author data
|
||||||
*/
|
*/
|
||||||
public readonly author?: APIEmbedAuthor;
|
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
|
* Received data about the embed provider
|
||||||
*/
|
*/
|
||||||
public readonly provider?: APIEmbedProvider;
|
public get provider() {
|
||||||
|
return this.data.provider;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The embed footer data
|
* The embed footer data
|
||||||
*/
|
*/
|
||||||
public readonly footer?: APIEmbedFooter;
|
public get footer(): EmbedFooterData | undefined {
|
||||||
|
if (!this.data.footer) return undefined;
|
||||||
public constructor(data: APIEmbed = {}) {
|
return {
|
||||||
this.title = data.title;
|
text: this.data.footer.text,
|
||||||
this.description = data.description;
|
iconURL: this.data.footer.icon_url,
|
||||||
this.url = data.url;
|
proxyIconURL: this.data.footer.proxy_icon_url,
|
||||||
this.color = data.color;
|
};
|
||||||
this.thumbnail = data.thumbnail;
|
|
||||||
this.image = data.image;
|
|
||||||
this.video = data.video;
|
|
||||||
this.author = data.author;
|
|
||||||
this.provider = data.provider;
|
|
||||||
this.footer = data.footer;
|
|
||||||
this.fields = data.fields ?? [];
|
|
||||||
|
|
||||||
if (data.timestamp) this.timestamp = new Date(data.timestamp).toISOString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -103,11 +156,11 @@ export class UnsafeEmbed implements APIEmbed, JSONEncodable<APIEmbed> {
|
|||||||
*/
|
*/
|
||||||
public get length(): number {
|
public get length(): number {
|
||||||
return (
|
return (
|
||||||
(this.title?.length ?? 0) +
|
(this.data.title?.length ?? 0) +
|
||||||
(this.description?.length ?? 0) +
|
(this.data.description?.length ?? 0) +
|
||||||
this.fields.reduce((prev, curr) => prev + curr.name.length + curr.value.length, 0) +
|
(this.data.fields?.reduce((prev, curr) => prev + curr.name.length + curr.value.length, 0) ?? 0) +
|
||||||
(this.footer?.text.length ?? 0) +
|
(this.data.footer?.text.length ?? 0) +
|
||||||
(this.author?.name.length ?? 0)
|
(this.data.author?.name.length ?? 0)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +179,9 @@ export class UnsafeEmbed implements APIEmbed, JSONEncodable<APIEmbed> {
|
|||||||
* @param fields The fields to add
|
* @param fields The fields to add
|
||||||
*/
|
*/
|
||||||
public addFields(...fields: APIEmbedField[]): this {
|
public addFields(...fields: APIEmbedField[]): this {
|
||||||
this.fields.push(...UnsafeEmbed.normalizeFields(...fields));
|
fields = UnsafeEmbed.normalizeFields(...fields);
|
||||||
|
if (this.data.fields) this.data.fields.push(...fields);
|
||||||
|
else this.data.fields = fields;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +193,9 @@ export class UnsafeEmbed implements APIEmbed, JSONEncodable<APIEmbed> {
|
|||||||
* @param fields The replacing field objects
|
* @param fields The replacing field objects
|
||||||
*/
|
*/
|
||||||
public spliceFields(index: number, deleteCount: number, ...fields: APIEmbedField[]): this {
|
public spliceFields(index: number, deleteCount: number, ...fields: APIEmbedField[]): this {
|
||||||
this.fields.splice(index, deleteCount, ...UnsafeEmbed.normalizeFields(...fields));
|
fields = UnsafeEmbed.normalizeFields(...fields);
|
||||||
|
if (this.data.fields) this.data.fields.splice(index, deleteCount, ...fields);
|
||||||
|
else this.data.fields = fields;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +204,7 @@ export class UnsafeEmbed implements APIEmbed, JSONEncodable<APIEmbed> {
|
|||||||
* @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, ...fields);
|
this.spliceFields(0, this.fields?.length ?? 0, ...fields);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,13 +213,13 @@ export class UnsafeEmbed implements APIEmbed, JSONEncodable<APIEmbed> {
|
|||||||
*
|
*
|
||||||
* @param options The options for the author
|
* @param options The options for the author
|
||||||
*/
|
*/
|
||||||
public setAuthor(options: AuthorOptions | null): this {
|
public setAuthor(options: EmbedAuthorOptions | null): this {
|
||||||
if (options === null) {
|
if (options === null) {
|
||||||
Reflect.set(this, 'author', undefined);
|
this.data.author = undefined;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Reflect.set(this, 'author', { name: options.name, url: options.url, icon_url: options.iconURL });
|
this.data.author = { name: options.name, url: options.url, icon_url: options.iconURL };
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +229,7 @@ export class UnsafeEmbed implements APIEmbed, JSONEncodable<APIEmbed> {
|
|||||||
* @param color The color of the embed
|
* @param color The color of the embed
|
||||||
*/
|
*/
|
||||||
public setColor(color: number | null): this {
|
public setColor(color: number | null): this {
|
||||||
Reflect.set(this, 'color', color ?? undefined);
|
this.data.color = color ?? undefined;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +239,7 @@ export class UnsafeEmbed implements APIEmbed, JSONEncodable<APIEmbed> {
|
|||||||
* @param description The description
|
* @param description The description
|
||||||
*/
|
*/
|
||||||
public setDescription(description: string | null): this {
|
public setDescription(description: string | null): this {
|
||||||
Reflect.set(this, 'description', description ?? undefined);
|
this.data.description = description ?? undefined;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,13 +248,13 @@ export class UnsafeEmbed implements APIEmbed, JSONEncodable<APIEmbed> {
|
|||||||
*
|
*
|
||||||
* @param options The options for the footer
|
* @param options The options for the footer
|
||||||
*/
|
*/
|
||||||
public setFooter(options: FooterOptions | null): this {
|
public setFooter(options: EmbedFooterOptions | null): this {
|
||||||
if (options === null) {
|
if (options === null) {
|
||||||
Reflect.set(this, 'footer', undefined);
|
this.data.footer = undefined;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Reflect.set(this, 'footer', { text: options.text, icon_url: options.iconURL });
|
this.data.footer = { text: options.text, icon_url: options.iconURL };
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +264,7 @@ export class UnsafeEmbed implements APIEmbed, JSONEncodable<APIEmbed> {
|
|||||||
* @param url The URL of the image
|
* @param url The URL of the image
|
||||||
*/
|
*/
|
||||||
public setImage(url: string | null): this {
|
public setImage(url: string | null): this {
|
||||||
Reflect.set(this, 'image', url ? { url } : undefined);
|
this.data.image = url ? { url } : undefined;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,7 +274,7 @@ export class UnsafeEmbed implements APIEmbed, JSONEncodable<APIEmbed> {
|
|||||||
* @param url The URL of the thumbnail
|
* @param url The URL of the thumbnail
|
||||||
*/
|
*/
|
||||||
public setThumbnail(url: string | null): this {
|
public setThumbnail(url: string | null): this {
|
||||||
Reflect.set(this, 'thumbnail', url ? { url } : undefined);
|
this.data.thumbnail = url ? { url } : undefined;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +284,7 @@ export class UnsafeEmbed implements APIEmbed, JSONEncodable<APIEmbed> {
|
|||||||
* @param timestamp The timestamp or date
|
* @param timestamp The timestamp or date
|
||||||
*/
|
*/
|
||||||
public setTimestamp(timestamp: number | Date | null = Date.now()): this {
|
public setTimestamp(timestamp: number | Date | null = Date.now()): this {
|
||||||
Reflect.set(this, 'timestamp', timestamp ? new Date(timestamp).toISOString() : undefined);
|
this.data.timestamp = timestamp ? new Date(timestamp).toISOString() : undefined;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +294,7 @@ export class UnsafeEmbed implements APIEmbed, JSONEncodable<APIEmbed> {
|
|||||||
* @param title The title
|
* @param title The title
|
||||||
*/
|
*/
|
||||||
public setTitle(title: string | null): this {
|
public setTitle(title: string | null): this {
|
||||||
Reflect.set(this, 'title', title ?? undefined);
|
this.data.title = title ?? undefined;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,7 +304,7 @@ export class UnsafeEmbed implements APIEmbed, JSONEncodable<APIEmbed> {
|
|||||||
* @param url The URL
|
* @param url The URL
|
||||||
*/
|
*/
|
||||||
public setURL(url: string | null): this {
|
public setURL(url: string | null): this {
|
||||||
Reflect.set(this, 'url', url ?? undefined);
|
this.data.url = url ?? undefined;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +312,7 @@ export class UnsafeEmbed implements APIEmbed, JSONEncodable<APIEmbed> {
|
|||||||
* Transforms the embed to a plain object
|
* Transforms the embed to a plain object
|
||||||
*/
|
*/
|
||||||
public toJSON(): APIEmbed {
|
public toJSON(): APIEmbed {
|
||||||
return { ...this };
|
return { ...this.data };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -724,7 +724,7 @@ client.on('interactionCreate', async interaction => {
|
|||||||
|
|
||||||
const button = new ButtonComponent();
|
const button = new ButtonComponent();
|
||||||
|
|
||||||
const actionRow = new ActionRow<ActionRowComponent>({ type: ComponentType.ActionRow, components: [button] });
|
const actionRow = new ActionRow<ActionRowComponent>({ type: ComponentType.ActionRow, components: [button.toJSON()] });
|
||||||
|
|
||||||
await interaction.reply({ content: 'Hi!', components: [actionRow] });
|
await interaction.reply({ content: 'Hi!', components: [actionRow] });
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user