@sapphire/framework
Version:
Discord bot framework built for advanced and amazing bots.
1 lines • 5.87 kB
Source Map (JSON)
{"version":3,"file":"message.mjs","names":[],"sources":["../../../../src/lib/resolvers/message.ts"],"sourcesContent":["import { ChannelMessageRegex, MessageLinkRegex, SnowflakeRegex } from '@sapphire/discord-utilities';\nimport {\n\tisAnyInteraction,\n\tisGuildBasedChannel,\n\tisNewsChannel,\n\tisStageChannel,\n\tisTextBasedChannel,\n\tisTextChannel,\n\ttype AnyInteraction,\n\ttype GuildBasedChannelTypes,\n\ttype TextBasedChannelTypes\n} from '@sapphire/discord.js-utilities';\nimport { container } from '@sapphire/pieces';\nimport { Result } from '@sapphire/result';\nimport type { Awaitable } from '@sapphire/utilities';\nimport { PermissionFlagsBits, type Message, type Snowflake, type User } from 'discord.js';\nimport { Identifiers } from '../errors/Identifiers';\n\n/**\n * Options to resolve a message from a string, given a certain context.\n */\nexport interface MessageResolverOptions {\n\t/**\n\t * Channel to resolve the message in.\n\t * @default message.channel\n\t */\n\tchannel?: TextBasedChannelTypes;\n\t/**\n\t * Base {@link Message} or {@link AnyInteraction} to resolve the message from (e.g. pick the channel if not given).\n\t */\n\tmessageOrInteraction: Message | AnyInteraction;\n\t/**\n\t * Whether to scan the entire guild cache for the message.\n\t * If channel is given with this option, this option is ignored.\n\t * @default false\n\t */\n\tscan?: boolean;\n}\n\nexport async function resolveMessage(parameter: string, options: MessageResolverOptions): Promise<Result<Message, Identifiers.ArgumentMessageError>> {\n\tconst message =\n\t\t(await resolveById(parameter, options)) ??\n\t\t(await resolveByLink(parameter, options)) ??\n\t\t(await resolveByChannelAndMessage(parameter, options));\n\n\tif (message) {\n\t\treturn Result.ok(message);\n\t}\n\n\treturn Result.err(Identifiers.ArgumentMessageError);\n}\n\nfunction resolveById(parameter: string, options: MessageResolverOptions): Awaitable<Message | null> {\n\tif (!SnowflakeRegex.test(parameter) || isStageChannel(options.messageOrInteraction.channel)) {\n\t\treturn null;\n\t}\n\n\tif (options.channel && !isStageChannel(options.channel)) {\n\t\treturn options.channel.messages.fetch(parameter as Snowflake);\n\t}\n\n\tif (options.scan && isGuildBasedChannel(options.messageOrInteraction.channel)) {\n\t\tfor (const channel of options.messageOrInteraction.channel.guild.channels.cache.values()) {\n\t\t\tif (!isTextBasedChannel(channel) || isStageChannel(channel)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst message = channel.messages.cache.get(parameter);\n\t\t\tif (message) {\n\t\t\t\treturn message;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn options.messageOrInteraction.channel?.messages.fetch(parameter as Snowflake) ?? null;\n}\n\nasync function resolveByLink(parameter: string, options: MessageResolverOptions): Promise<Message | null> {\n\tif (!options.messageOrInteraction.guild) {\n\t\treturn null;\n\t}\n\n\tconst matches = MessageLinkRegex.exec(parameter);\n\tif (!matches) {\n\t\treturn null;\n\t}\n\n\tconst [, guildId, channelId, messageId] = matches;\n\n\tconst guild = container.client.guilds.cache.get(guildId as Snowflake);\n\tif (guild !== options.messageOrInteraction.guild) {\n\t\treturn null;\n\t}\n\n\treturn getMessageFromChannel(\n\t\tchannelId,\n\t\tmessageId,\n\t\tisAnyInteraction(options.messageOrInteraction) ? options.messageOrInteraction.user : options.messageOrInteraction.author\n\t);\n}\n\nasync function resolveByChannelAndMessage(parameter: string, options: MessageResolverOptions): Promise<Message | null> {\n\tconst result = ChannelMessageRegex.exec(parameter)?.groups;\n\n\tif (!result) {\n\t\treturn null;\n\t}\n\n\treturn getMessageFromChannel(\n\t\tresult.channelId,\n\t\tresult.messageId,\n\t\tisAnyInteraction(options.messageOrInteraction) ? options.messageOrInteraction.user : options.messageOrInteraction.author\n\t);\n}\n\nasync function getMessageFromChannel(channelId: Snowflake, messageId: Snowflake, originalAuthor: User): Promise<Message | null> {\n\tconst channel = container.client.channels.cache.get(channelId) as GuildBasedChannelTypes;\n\tif (!channel) {\n\t\treturn null;\n\t}\n\n\tif (!(isNewsChannel(channel) || isTextChannel(channel))) {\n\t\treturn null;\n\t}\n\n\tif (!channel.viewable) {\n\t\treturn null;\n\t}\n\n\tif (!channel.permissionsFor(originalAuthor)?.has(PermissionFlagsBits.ViewChannel)) {\n\t\treturn null;\n\t}\n\n\treturn channel.messages.fetch(messageId);\n}\n"],"mappings":";;;;;;;;AAuCA,eAAsB,eAAe,WAAmB,SAA6F;CACpJ,MAAM,UACJ,MAAM,YAAY,WAAW,QAAQ,IACrC,MAAM,cAAc,WAAW,QAAQ,IACvC,MAAM,2BAA2B,WAAW,QAAQ;AAEtD,KAAI,QACH,QAAO,OAAO,GAAG,QAAQ;AAG1B,QAAO,OAAO,IAAI,YAAY,qBAAqB;;AAGpD,SAAS,YAAY,WAAmB,SAA4D;AACnG,KAAI,CAAC,eAAe,KAAK,UAAU,IAAI,eAAe,QAAQ,qBAAqB,QAAQ,CAC1F,QAAO;AAGR,KAAI,QAAQ,WAAW,CAAC,eAAe,QAAQ,QAAQ,CACtD,QAAO,QAAQ,QAAQ,SAAS,MAAM,UAAuB;AAG9D,KAAI,QAAQ,QAAQ,oBAAoB,QAAQ,qBAAqB,QAAQ,CAC5E,MAAK,MAAM,WAAW,QAAQ,qBAAqB,QAAQ,MAAM,SAAS,MAAM,QAAQ,EAAE;AACzF,MAAI,CAAC,mBAAmB,QAAQ,IAAI,eAAe,QAAQ,CAC1D;EAGD,MAAM,UAAU,QAAQ,SAAS,MAAM,IAAI,UAAU;AACrD,MAAI,QACH,QAAO;;AAKV,QAAO,QAAQ,qBAAqB,SAAS,SAAS,MAAM,UAAuB,IAAI;;AAGxF,eAAe,cAAc,WAAmB,SAA0D;AACzG,KAAI,CAAC,QAAQ,qBAAqB,MACjC,QAAO;CAGR,MAAM,UAAU,iBAAiB,KAAK,UAAU;AAChD,KAAI,CAAC,QACJ,QAAO;CAGR,MAAM,GAAG,SAAS,WAAW,aAAa;AAG1C,KADc,UAAU,OAAO,OAAO,MAAM,IAAI,QAAqB,KACvD,QAAQ,qBAAqB,MAC1C,QAAO;AAGR,QAAO,sBACN,WACA,WACA,iBAAiB,QAAQ,qBAAqB,GAAG,QAAQ,qBAAqB,OAAO,QAAQ,qBAAqB,OAClH;;AAGF,eAAe,2BAA2B,WAAmB,SAA0D;CACtH,MAAM,SAAS,oBAAoB,KAAK,UAAU,EAAE;AAEpD,KAAI,CAAC,OACJ,QAAO;AAGR,QAAO,sBACN,OAAO,WACP,OAAO,WACP,iBAAiB,QAAQ,qBAAqB,GAAG,QAAQ,qBAAqB,OAAO,QAAQ,qBAAqB,OAClH;;AAGF,eAAe,sBAAsB,WAAsB,WAAsB,gBAA+C;CAC/H,MAAM,UAAU,UAAU,OAAO,SAAS,MAAM,IAAI,UAAU;AAC9D,KAAI,CAAC,QACJ,QAAO;AAGR,KAAI,EAAE,cAAc,QAAQ,IAAI,cAAc,QAAQ,EACrD,QAAO;AAGR,KAAI,CAAC,QAAQ,SACZ,QAAO;AAGR,KAAI,CAAC,QAAQ,eAAe,eAAe,EAAE,IAAI,oBAAoB,YAAY,CAChF,QAAO;AAGR,QAAO,QAAQ,SAAS,MAAM,UAAU"}