From d387f669ab9da9f41bea24caab81005db74b82aa Mon Sep 17 00:00:00 2001 From: Domin-MND <69919939+domin-mnd@users.noreply.github.com> Date: Sat, 21 Oct 2023 11:16:58 +0300 Subject: [PATCH 01/11] more descriptive djs adapter methods --- .../library/core/reacord-discord-js.ts | 151 +++++++++++++++--- packages/reacord/library/core/reacord.tsx | 7 +- packages/reacord/test/test-adapter.ts | 6 +- 3 files changed, 140 insertions(+), 24 deletions(-) diff --git a/packages/reacord/library/core/reacord-discord-js.ts b/packages/reacord/library/core/reacord-discord-js.ts index 6e48763..5647e0b 100644 --- a/packages/reacord/library/core/reacord-discord-js.ts +++ b/packages/reacord/library/core/reacord-discord-js.ts @@ -24,12 +24,46 @@ import type { ReacordInstance } from "./instance" import type { ReacordConfig } from "./reacord" import { Reacord } from "./reacord" -interface SendOptions { +/** + * Options for the channel message. + * + * @see https://reacord.mapleleaf.dev/guides/sending-messages + */ +export interface LegacyCreateChannelMessageOptions + extends CreateChannelMessageOptions { + /** + * Send message as a reply. Requires the use of message event instead of + * channel id provided as argument. + * + * @deprecated Use reacord.createMessageReply() + */ reply?: boolean } -interface ReplyOptions { +/** + * Options for the channel message. + * + * @see https://reacord.mapleleaf.dev/guides/sending-messages + */ +export interface CreateChannelMessageOptions {} + +/** + * Options for the message reply method. + * + * @see https://reacord.mapleleaf.dev/guides/sending-messages + */ +export interface CreateMessageReplyOptions {} + +/** + * Custom options for the interaction reply method. + * + * @see https://reacord.mapleleaf.dev/guides/sending-messages + */ +export interface CreateInteractionReplyOptions { + /** Whether to send interaction reply as _ephemeral_. */ ephemeral?: boolean + /** Whether to use text-to-speech. */ + tts?: boolean } /** @@ -53,18 +87,81 @@ export class ReacordDiscordJs extends Reacord { }) } + /** + * Sends a message to a channel. + * + * @param {Discord.Channel} target - Discord channel object. + * @param {CreateChannelMessageOptions} [options={}] - Options for the channel + * message. Default is `{}` + * @param {React.ReactNode} [content] - Initial React node content to render. + * @see https://reacord.mapleleaf.dev/guides/sending-messages + */ + public createChannelMessage( + target: Discord.Channel, + options: CreateChannelMessageOptions = {}, + content?: React.ReactNode, + ): ReacordInstance { + return this.createInstance( + this.createChannelMessageRenderer(target, options), + content, + ) + } + + /** + * Replies to a message by sending a message. + * + * @param {Discord.Message} message - Discord message event object. + * @param {CreateMessageReplyOptions} [options={}] - Options for the message + * reply method. Default is `{}` + * @param {React.ReactNode} [content] - Initial React node content to render. + * @see https://reacord.mapleleaf.dev/guides/sending-messages + */ + public createMessageReply( + message: Discord.Message, + options: CreateMessageReplyOptions = {}, + content?: React.ReactNode, + ): ReacordInstance { + return this.createInstance( + this.createMessageReplyRenderer(message, options), + content, + ) + } + + /** + * Replies to a command interaction by sending a message. + * + * @param {Discord.CommandInteraction} interaction - Discord command + * interaction object. + * @param {CreateInteractionReplyOptions} [options={}] - Custom options for + * the interaction reply method. Default is `{}` + * @param {React.ReactNode} [content] - Initial React node content to render. + * @see https://reacord.mapleleaf.dev/guides/sending-messages + */ + public createInteractionReply( + interaction: Discord.CommandInteraction, + options: CreateInteractionReplyOptions = {}, + content?: React.ReactNode, + ): ReacordInstance { + return this.createInstance( + this.createInteractionReplyRenderer(interaction, options), + content, + ) + } + /** * Sends a message to a channel. Alternatively replies to message event. * + * @deprecated Use reacord.createChannelMessage() or + * reacord.createMessageReply() instead. * @see https://reacord.mapleleaf.dev/guides/sending-messages */ - override send( - channelId: string, + public send( + event: string | Discord.Message, initialContent?: React.ReactNode, - options?: SendOptions, + options: LegacyCreateChannelMessageOptions = {}, ): ReacordInstance { return this.createInstance( - this.createChannelRenderer(channelId, options), + this.createMessageReplyRenderer(event, options), initialContent, ) } @@ -72,12 +169,13 @@ export class ReacordDiscordJs extends Reacord { /** * Sends a message as a reply to a command interaction. * + * @deprecated Use reacord.createInteractionReply() instead. * @see https://reacord.mapleleaf.dev/guides/sending-messages */ - override reply( + public reply( interaction: Discord.CommandInteraction, initialContent?: React.ReactNode, - options?: ReplyOptions, + options: CreateInteractionReplyOptions = {}, ): ReacordInstance { return this.createInstance( this.createInteractionReplyRenderer(interaction, options), @@ -88,13 +186,14 @@ export class ReacordDiscordJs extends Reacord { /** * Sends an ephemeral message as a reply to a command interaction. * - * @deprecated Use reacord.reply(interaction, content, { ephemeral: true }) + * @deprecated Use reacord.createInteractionReply(interaction, content, { + * ephemeral: true }) * @see https://reacord.mapleleaf.dev/guides/sending-messages */ - override ephemeralReply( + public ephemeralReply( interaction: Discord.CommandInteraction, initialContent?: React.ReactNode, - options?: Omit, + options?: Omit, ): ReacordInstance { return this.createInstance( this.createInteractionReplyRenderer(interaction, { @@ -105,9 +204,25 @@ export class ReacordDiscordJs extends Reacord { ) } - private createChannelRenderer( + private createChannelMessageRenderer( + channel: Discord.Channel, + _opts?: CreateMessageReplyOptions, + ) { + return new ChannelMessageRenderer({ + send: async (options) => { + if (!channel.isTextBased()) { + raise(`Channel ${channel.id} is not a text channel`) + } + + const message = await channel.send(getDiscordMessageOptions(options)) + return createReacordMessage(message) + }, + }) + } + + private createMessageReplyRenderer( event: string | Discord.Message, - opts?: SendOptions, + opts: CreateChannelMessageOptions | LegacyCreateChannelMessageOptions, ) { return new ChannelMessageRenderer({ send: async (options) => { @@ -124,7 +239,7 @@ export class ReacordDiscordJs extends Reacord { raise(`Channel ${channel.id} is not a text channel`) } - if (opts?.reply) { + if ("reply" in opts && opts.reply) { if (typeof event === "string") { raise("Cannot send reply with channel ID provided") } @@ -142,7 +257,7 @@ export class ReacordDiscordJs extends Reacord { interaction: | Discord.CommandInteraction | Discord.MessageComponentInteraction, - opts?: ReplyOptions, + opts: CreateInteractionReplyOptions, ) { return new InteractionReplyRenderer({ type: "command", @@ -150,16 +265,16 @@ export class ReacordDiscordJs extends Reacord { reply: async (options) => { const message = await interaction.reply({ ...getDiscordMessageOptions(options), + ...opts, fetchReply: true, - ephemeral: opts?.ephemeral, }) return createReacordMessage(message) }, followUp: async (options) => { const message = await interaction.followUp({ ...getDiscordMessageOptions(options), + ...opts, fetchReply: true, - ephemeral: opts?.ephemeral, }) return createReacordMessage(message) }, @@ -285,7 +400,7 @@ export class ReacordDiscordJs extends Reacord { reply: (content?: ReactNode) => this.createInstance( - this.createInteractionReplyRenderer(interaction), + this.createInteractionReplyRenderer(interaction, {}), content, ), diff --git a/packages/reacord/library/core/reacord.tsx b/packages/reacord/library/core/reacord.tsx index 02eba7e..0b7de17 100644 --- a/packages/reacord/library/core/reacord.tsx +++ b/packages/reacord/library/core/reacord.tsx @@ -23,9 +23,10 @@ export abstract class Reacord { constructor(private readonly config: ReacordConfig = {}) {} - abstract send(...args: unknown[]): ReacordInstance - abstract reply(...args: unknown[]): ReacordInstance - abstract ephemeralReply(...args: unknown[]): ReacordInstance + // There's no more need in abstract methods + // abstract send(...args: unknown[]): ReacordInstance + // abstract reply(...args: unknown[]): ReacordInstance + // abstract ephemeralReply(...args: unknown[]): ReacordInstance protected handleComponentInteraction(interaction: ComponentInteraction) { for (const renderer of this.renderers) { diff --git a/packages/reacord/test/test-adapter.ts b/packages/reacord/test/test-adapter.ts index b0675d9..7ddf6a7 100644 --- a/packages/reacord/test/test-adapter.ts +++ b/packages/reacord/test/test-adapter.ts @@ -42,14 +42,14 @@ export class ReacordTester extends Reacord { return [...this.messageContainer] } - override send(initialContent?: ReactNode): ReacordInstance { + public send(initialContent?: ReactNode): ReacordInstance { return this.createInstance( new ChannelMessageRenderer(new TestChannel(this.messageContainer)), initialContent, ) } - override reply(initialContent?: ReactNode): ReacordInstance { + public reply(initialContent?: ReactNode): ReacordInstance { return this.createInstance( new InteractionReplyRenderer( new TestCommandInteraction(this.messageContainer), @@ -58,7 +58,7 @@ export class ReacordTester extends Reacord { ) } - override ephemeralReply(initialContent?: ReactNode): ReacordInstance { + public ephemeralReply(initialContent?: ReactNode): ReacordInstance { return this.reply(initialContent) } From 453192cc962e945474944e0cd2f7b9abfe102e56 Mon Sep 17 00:00:00 2001 From: Domin-MND <69919939+domin-mnd@users.noreply.github.com> Date: Mon, 23 Oct 2023 11:51:59 +0300 Subject: [PATCH 02/11] cleanup --- .../library/core/reacord-discord-js.ts | 22 ++++++++----------- packages/reacord/library/core/reacord.tsx | 5 ----- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/packages/reacord/library/core/reacord-discord-js.ts b/packages/reacord/library/core/reacord-discord-js.ts index 5647e0b..7c6ed3d 100644 --- a/packages/reacord/library/core/reacord-discord-js.ts +++ b/packages/reacord/library/core/reacord-discord-js.ts @@ -90,10 +90,9 @@ export class ReacordDiscordJs extends Reacord { /** * Sends a message to a channel. * - * @param {Discord.Channel} target - Discord channel object. - * @param {CreateChannelMessageOptions} [options={}] - Options for the channel - * message. Default is `{}` - * @param {React.ReactNode} [content] - Initial React node content to render. + * @param target - Discord channel object. + * @param [options] - Options for the channel message + * @param [content] - Initial React node content to render. * @see https://reacord.mapleleaf.dev/guides/sending-messages */ public createChannelMessage( @@ -110,10 +109,9 @@ export class ReacordDiscordJs extends Reacord { /** * Replies to a message by sending a message. * - * @param {Discord.Message} message - Discord message event object. - * @param {CreateMessageReplyOptions} [options={}] - Options for the message - * reply method. Default is `{}` - * @param {React.ReactNode} [content] - Initial React node content to render. + * @param message - Discord message event object. + * @param [options] - Options for the message reply method. + * @param [content] - Initial React node content to render. * @see https://reacord.mapleleaf.dev/guides/sending-messages */ public createMessageReply( @@ -130,11 +128,9 @@ export class ReacordDiscordJs extends Reacord { /** * Replies to a command interaction by sending a message. * - * @param {Discord.CommandInteraction} interaction - Discord command - * interaction object. - * @param {CreateInteractionReplyOptions} [options={}] - Custom options for - * the interaction reply method. Default is `{}` - * @param {React.ReactNode} [content] - Initial React node content to render. + * @param interaction - Discord command interaction object. + * @param [options] - Custom options for the interaction reply method. + * @param [content] - Initial React node content to render. * @see https://reacord.mapleleaf.dev/guides/sending-messages */ public createInteractionReply( diff --git a/packages/reacord/library/core/reacord.tsx b/packages/reacord/library/core/reacord.tsx index 0b7de17..8d63c23 100644 --- a/packages/reacord/library/core/reacord.tsx +++ b/packages/reacord/library/core/reacord.tsx @@ -23,11 +23,6 @@ export abstract class Reacord { constructor(private readonly config: ReacordConfig = {}) {} - // There's no more need in abstract methods - // abstract send(...args: unknown[]): ReacordInstance - // abstract reply(...args: unknown[]): ReacordInstance - // abstract ephemeralReply(...args: unknown[]): ReacordInstance - protected handleComponentInteraction(interaction: ComponentInteraction) { for (const renderer of this.renderers) { if (renderer.handleComponentInteraction(interaction)) return From f998a0e09aea94cb7419f9d8626cc95b9e51731b Mon Sep 17 00:00:00 2001 From: Domin-MND <69919939+domin-mnd@users.noreply.github.com> Date: Mon, 23 Oct 2023 12:24:24 +0300 Subject: [PATCH 03/11] fix djs manual test --- .../reacord/scripts/discordjs-manual-test.tsx | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/reacord/scripts/discordjs-manual-test.tsx b/packages/reacord/scripts/discordjs-manual-test.tsx index 3a06058..2a3fbe0 100644 --- a/packages/reacord/scripts/discordjs-manual-test.tsx +++ b/packages/reacord/scripts/discordjs-manual-test.tsx @@ -50,7 +50,7 @@ const createTest = async ( } await createTest("basic", (channel) => { - reacord.send(channel.id, "Hello, world!") + reacord.createChannelMessage(channel, {}, "Hello, world!") }) await createTest("counter", (channel) => { @@ -73,7 +73,7 @@ await createTest("counter", (channel) => { ) } - reacord.send(channel.id, ) + reacord.createChannelMessage(channel, {}, ) }) await createTest("select", (channel) => { @@ -102,8 +102,9 @@ await createTest("select", (channel) => { ) } - const instance = reacord.send( - channel.id, + const instance = reacord.createChannelMessage( + channel, + {}, { instance.render(`you chose ${value}`) @@ -114,8 +115,9 @@ await createTest("select", (channel) => { }) await createTest("ephemeral button", (channel) => { - reacord.send( - channel.id, + reacord.createChannelMessage( + channel, + {}, <>