diff options
Diffstat (limited to 'src/lib/common')
| -rw-r--r-- | src/lib/common/AutoMod.ts | 51 | ||||
| -rw-r--r-- | src/lib/common/ButtonPaginator.ts | 47 | ||||
| -rw-r--r-- | src/lib/common/ConfirmationPrompt.ts | 27 | ||||
| -rw-r--r-- | src/lib/common/DeleteButton.ts | 27 | ||||
| -rw-r--r-- | src/lib/common/HighlightManager.ts | 16 | ||||
| -rw-r--r-- | src/lib/common/Sentry.ts | 2 | ||||
| -rw-r--r-- | src/lib/common/util/Arg.ts | 269 | ||||
| -rw-r--r-- | src/lib/common/util/Format.ts | 187 | ||||
| -rw-r--r-- | src/lib/common/util/Moderation.ts | 517 |
9 files changed, 566 insertions, 577 deletions
diff --git a/src/lib/common/AutoMod.ts b/src/lib/common/AutoMod.ts index 982e0e8..7f19e63 100644 --- a/src/lib/common/AutoMod.ts +++ b/src/lib/common/AutoMod.ts @@ -1,4 +1,4 @@ -import { banResponse, Moderation } from '#lib'; +import { banResponse, codeblock, colors, emojis, format, formatError, getShared, Moderation, resolveNonCachedUser } from '#lib'; import assert from 'assert'; import chalk from 'chalk'; import { @@ -18,11 +18,6 @@ import { */ export class AutoMod { /** - * The message to check for blacklisted phrases on - */ - private message: Message; - - /** * Whether or not a punishment has already been given to the user */ private punished = false; @@ -30,8 +25,12 @@ export class AutoMod { /** * @param message The message to check and potentially perform automod actions to */ - public constructor(message: Message) { - this.message = message; + public constructor( + /** + * The message to check for blacklisted phrases on + */ + private message: Message + ) { if (message.author.id === client.user?.id) return; void this.handle(); } @@ -57,9 +56,9 @@ export class AutoMod { traditional: { if (this.isImmune) break traditional; - const badLinksArray = util.getShared('badLinks'); - const badLinksSecretArray = util.getShared('badLinksSecret'); - const badWordsRaw = util.getShared('badWords'); + const badLinksArray = getShared('badLinks'); + const badLinksSecretArray = getShared('badLinksSecret'); + const badWordsRaw = getShared('badWords'); const customAutomodPhrases = (await this.message.guild.getSetting('autoModPhases')) ?? []; const uniqueLinks = [...new Set([...badLinksArray, ...badLinksSecretArray])]; @@ -90,8 +89,8 @@ export class AutoMod { embeds: [ { title: 'AutoMod Error', - description: `Unable to find severity information for ${util.format.inlineCode(highestOffence.match)}`, - color: util.colors.error + description: `Unable to find severity information for ${format.inlineCode(highestOffence.match)}`, + color: colors.error } ] }); @@ -168,7 +167,7 @@ export class AutoMod { .setDescription( `**User:** ${this.message.author} (${this.message.author.tag})\n**Sent From:** <#${this.message.channel.id}> [Jump to context](${this.message.url})` ) - .addFields([{ name: 'Message Content', value: `${await util.codeblock(this.message.content, 1024)}` }]) + .addFields([{ name: 'Message Content', value: `${await codeblock(this.message.content, 1024)}` }]) .setColor(color) .setTimestamp() ], @@ -252,13 +251,13 @@ export class AutoMod { let color; switch (highestOffence.severity) { case Severity.DELETE: { - color = util.colors.lightGray; + color = colors.lightGray; void this.message.delete().catch((e) => deleteError.bind(this, e)); this.punished = true; break; } case Severity.WARN: { - color = util.colors.yellow; + color = colors.yellow; void this.message.delete().catch((e) => deleteError.bind(this, e)); void this.message.member?.bushWarn({ moderator: this.message.guild!.members.me!, @@ -268,7 +267,7 @@ export class AutoMod { break; } case Severity.TEMP_MUTE: { - color = util.colors.orange; + color = colors.orange; void this.message.delete().catch((e) => deleteError.bind(this, e)); void this.message.member?.bushMute({ moderator: this.message.guild!.members.me!, @@ -279,7 +278,7 @@ export class AutoMod { break; } case Severity.PERM_MUTE: { - color = util.colors.red; + color = colors.red; void this.message.delete().catch((e) => deleteError.bind(this, e)); void this.message.member?.bushMute({ moderator: this.message.guild!.members.me!, @@ -302,8 +301,8 @@ export class AutoMod { { title: 'AutoMod Error', description: `Unable to delete triggered message.`, - fields: [{ name: 'Error', value: await util.codeblock(`${util.formatError(e)}`, 1024, 'js', true) }], - color: util.colors.error + fields: [{ name: 'Error', value: await codeblock(`${formatError(e)}`, 1024, 'js', true) }], + color: colors.error } ] }); @@ -333,7 +332,7 @@ export class AutoMod { this.message.channel.id }> [Jump to context](${this.message.url})\n**Blacklisted Words:** ${offences.map((o) => `\`${o.match}\``).join(', ')}` ) - .addFields([{ name: 'Message Content', value: `${await util.codeblock(this.message.content, 1024)}` }]) + .addFields([{ name: 'Message Content', value: `${await codeblock(this.message.content, 1024)}` }]) .setColor(color) .setTimestamp() .setAuthor({ name: this.message.author.tag, url: this.message.author.displayAvatarURL() }) @@ -360,7 +359,7 @@ export class AutoMod { public static async handleInteraction(interaction: ButtonInteraction) { if (!interaction.memberPermissions?.has(PermissionFlagsBits.BanMembers)) return interaction.reply({ - content: `${util.emojis.error} You are missing the **Ban Members** permission.`, + content: `${emojis.error} You are missing the **Ban Members** permission.`, ephemeral: true }); const [action, userId, reason] = interaction.customId.replace('automod;', '').split(';'); @@ -387,20 +386,20 @@ export class AutoMod { evidence: (interaction.message as Message).url ?? undefined }); - const victimUserFormatted = (await util.resolveNonCachedUser(userId))?.tag ?? userId; + const victimUserFormatted = (await resolveNonCachedUser(userId))?.tag ?? userId; if (result === banResponse.SUCCESS) return interaction.reply({ - content: `${util.emojis.success} Successfully banned **${victimUserFormatted}**.`, + content: `${emojis.success} Successfully banned **${victimUserFormatted}**.`, ephemeral: true }); else if (result === banResponse.DM_ERROR) return interaction.reply({ - content: `${util.emojis.warn} Banned ${victimUserFormatted} however I could not send them a dm.`, + content: `${emojis.warn} Banned ${victimUserFormatted} however I could not send them a dm.`, ephemeral: true }); else return interaction.reply({ - content: `${util.emojis.error} Could not ban **${victimUserFormatted}**: \`${result}\` .`, + content: `${emojis.error} Could not ban **${victimUserFormatted}**: \`${result}\` .`, ephemeral: true }); } diff --git a/src/lib/common/ButtonPaginator.ts b/src/lib/common/ButtonPaginator.ts index 64870cf..9560247 100644 --- a/src/lib/common/ButtonPaginator.ts +++ b/src/lib/common/ButtonPaginator.ts @@ -15,26 +15,6 @@ import { */ export class ButtonPaginator { /** - * The message that triggered the command - */ - protected message: CommandMessage | SlashMessage; - - /** - * The embeds to paginate - */ - protected embeds: EmbedBuilder[] | APIEmbed[]; - - /** - * The optional text to send with the paginator - */ - protected text: string | null; - - /** - * Whether the paginator message gets deleted when the exit button is pressed - */ - protected deleteOnExit: boolean; - - /** * The current page of the paginator */ protected curPage: number; @@ -52,16 +32,27 @@ export class ButtonPaginator { * @param startOn The page to start from (**not** the index) */ protected constructor( - message: CommandMessage | SlashMessage, - embeds: EmbedBuilder[] | APIEmbed[], - text: string | null, - deleteOnExit: boolean, + /** + * The message that triggered the command + */ + protected message: CommandMessage | SlashMessage, + + /** + * The embeds to paginate + */ + protected embeds: EmbedBuilder[] | APIEmbed[], + + /** + * The optional text to send with the paginator + */ + protected text: string | null, + + /** + * Whether the paginator message gets deleted when the exit button is pressed + */ + protected deleteOnExit: boolean, startOn: number ) { - this.message = message; - this.embeds = embeds; - this.text = text ? text : null; - this.deleteOnExit = deleteOnExit; this.curPage = startOn - 1; // add footers diff --git a/src/lib/common/ConfirmationPrompt.ts b/src/lib/common/ConfirmationPrompt.ts index c95dbbc..4593d24 100644 --- a/src/lib/common/ConfirmationPrompt.ts +++ b/src/lib/common/ConfirmationPrompt.ts @@ -6,23 +6,20 @@ import { ActionRowBuilder, ButtonBuilder, ButtonStyle, type MessageComponentInte */ export class ConfirmationPrompt { /** - * Options for sending the message - */ - protected messageOptions: MessageOptions; - - /** - * The message that triggered the command - */ - protected message: CommandMessage | SlashMessage; - - /** * @param message The message to respond to - * @param options The send message options + * @param messageOptions The send message options */ - protected constructor(message: CommandMessage | SlashMessage, messageOptions: MessageOptions) { - this.message = message; - this.messageOptions = messageOptions; - } + protected constructor( + /** + * The message that triggered the command + */ + protected message: CommandMessage | SlashMessage, + + /** + * Options for sending the message + */ + protected messageOptions: MessageOptions + ) {} /** * Sends a message with buttons for the user to confirm or cancel the action. diff --git a/src/lib/common/DeleteButton.ts b/src/lib/common/DeleteButton.ts index 91f4bfa..b561d94 100644 --- a/src/lib/common/DeleteButton.ts +++ b/src/lib/common/DeleteButton.ts @@ -15,23 +15,20 @@ import { */ export class DeleteButton { /** - * Options for sending the message - */ - protected messageOptions: MessageOptions; - - /** - * The message that triggered the command - */ - protected message: CommandMessage | SlashMessage; - - /** * @param message The message to respond to - * @param options The send message options + * @param messageOptions The send message options */ - protected constructor(message: CommandMessage | SlashMessage, options: MessageOptions) { - this.message = message; - this.messageOptions = options; - } + protected constructor( + /** + * The message that triggered the command + */ + protected message: CommandMessage | SlashMessage, + + /** + * Options for sending the message + */ + protected messageOptions: MessageOptions + ) {} /** * Sends a message with a button for the user to delete it. diff --git a/src/lib/common/HighlightManager.ts b/src/lib/common/HighlightManager.ts index fdec322..caaa6a5 100644 --- a/src/lib/common/HighlightManager.ts +++ b/src/lib/common/HighlightManager.ts @@ -1,7 +1,7 @@ -import { Highlight, type HighlightWord } from '#lib'; +import { addToArray, format, Highlight, removeFromArray, timestamp, type HighlightWord } from '#lib'; import assert from 'assert'; import { Collection, type Message, type Snowflake } from 'discord.js'; -import { Time } from '../utils/BushConstants.js'; +import { colors, Time } from '../utils/BushConstants.js'; const NOTIFY_COOLDOWN = 5 * Time.Minute; const OWNER_NOTIFY_COOLDOWN = 1 * Time.Minute; @@ -162,7 +162,7 @@ export class HighlightManager { if (highlight.words.some((w) => w.word === hl.word)) return `You have already highlighted "${hl.word}".`; - highlight.words = util.addToArray(highlight.words, hl); + highlight.words = addToArray(highlight.words, hl); return Boolean(await highlight.save().catch(() => false)); } @@ -189,7 +189,7 @@ export class HighlightManager { const toRemove = highlight.words.find((w) => w.word === hl); if (!toRemove) return `Uhhhhh... This shouldn't happen.`; - highlight.words = util.removeFromArray(highlight.words, toRemove); + highlight.words = removeFromArray(highlight.words, toRemove); return Boolean(await highlight.save().catch(() => false)); } @@ -271,20 +271,18 @@ export class HighlightManager { return client.users .send(user, { // eslint-disable-next-line @typescript-eslint/no-base-to-string - content: `In ${util.format.input(message.guild.name)} ${message.channel}, your highlight "${hl.word}" was matched:`, + content: `In ${format.input(message.guild.name)} ${message.channel}, your highlight "${hl.word}" was matched:`, embeds: [ { description: [...recentMessages, message] .map( (m) => - `${util.timestamp(m.createdAt, 't')} ${util.format.input(`${m.author.tag}:`)} ${m.cleanContent - .trim() - .substring(0, 512)}` + `${timestamp(m.createdAt, 't')} ${format.input(`${m.author.tag}:`)} ${m.cleanContent.trim().substring(0, 512)}` ) .join('\n'), author: { name: hl.regex ? `/${hl.word}/gi` : hl.word }, fields: [{ name: 'Source message', value: `[Jump to message](${message.url})` }], - color: util.colors.default, + color: colors.default, footer: { text: 'Triggered' }, timestamp: message.createdAt.toISOString() } diff --git a/src/lib/common/Sentry.ts b/src/lib/common/Sentry.ts index e18555b..34bc06f 100644 --- a/src/lib/common/Sentry.ts +++ b/src/lib/common/Sentry.ts @@ -1,7 +1,7 @@ import { RewriteFrames } from '@sentry/integrations'; import * as SentryNode from '@sentry/node'; import { Integrations } from '@sentry/node'; -import config from './../../config/options.js'; +import config from '../../../config/options.js'; export class Sentry { public constructor(rootdir: string) { diff --git a/src/lib/common/util/Arg.ts b/src/lib/common/util/Arg.ts index 51d8065..a7795b1 100644 --- a/src/lib/common/util/Arg.ts +++ b/src/lib/common/util/Arg.ts @@ -9,155 +9,150 @@ import { Argument, type Flag, type ParsedValuePredicate } from 'discord-akairo'; import { type Message } from 'discord.js'; /** - * A wrapper for the {@link Argument} class that adds custom typings. + * Casts a phrase to this argument's type. + * @param type - The type to cast to. + * @param message - Message that called the command. + * @param phrase - Phrase to process. */ -export class Arg { - /** - * Casts a phrase to this argument's type. - * @param type - The type to cast to. - * @param message - Message that called the command. - * @param phrase - Phrase to process. - */ - public static async cast<T extends ATC>(type: T, message: CommandMessage | SlashMessage, phrase: string): Promise<ATCR<T>>; - public static async cast<T extends KBAT>(type: T, message: CommandMessage | SlashMessage, phrase: string): Promise<BAT[T]>; - public static async cast(type: AT | ATC, message: CommandMessage | SlashMessage, phrase: string): Promise<any>; - public static async cast(type: ATC | AT, message: CommandMessage | SlashMessage, phrase: string): Promise<any> { - return Argument.cast(type as any, client.commandHandler.resolver, message as Message, phrase); - } +export async function cast<T extends ATC>(type: T, message: CommandMessage | SlashMessage, phrase: string): Promise<ATCR<T>>; +export async function cast<T extends KBAT>(type: T, message: CommandMessage | SlashMessage, phrase: string): Promise<BAT[T]>; +export async function cast(type: AT | ATC, message: CommandMessage | SlashMessage, phrase: string): Promise<any>; +export async function cast(type: ATC | AT, message: CommandMessage | SlashMessage, phrase: string): Promise<any> { + return Argument.cast(type as any, client.commandHandler.resolver, message as Message, phrase); +} - /** - * Creates a type that is the left-to-right composition of the given types. - * If any of the types fails, the entire composition fails. - * @param types - Types to use. - */ - public static compose<T extends ATC>(...types: T[]): ATCATCR<T>; - public static compose<T extends KBAT>(...types: T[]): ATCBAT<T>; - public static compose(...types: (AT | ATC)[]): ATC; - public static compose(...types: (AT | ATC)[]): ATC { - return Argument.compose(...(types as any)); - } +/** + * Creates a type that is the left-to-right composition of the given types. + * If any of the types fails, the entire composition fails. + * @param types - Types to use. + */ +export function compose<T extends ATC>(...types: T[]): ATCATCR<T>; +export function compose<T extends KBAT>(...types: T[]): ATCBAT<T>; +export function compose(...types: (AT | ATC)[]): ATC; +export function compose(...types: (AT | ATC)[]): ATC { + return Argument.compose(...(types as any)); +} - /** - * Creates a type that is the left-to-right composition of the given types. - * If any of the types fails, the composition still continues with the failure passed on. - * @param types - Types to use. - */ - public static composeWithFailure<T extends ATC>(...types: T[]): ATCATCR<T>; - public static composeWithFailure<T extends KBAT>(...types: T[]): ATCBAT<T>; - public static composeWithFailure(...types: (AT | ATC)[]): ATC; - public static composeWithFailure(...types: (AT | ATC)[]): ATC { - return Argument.composeWithFailure(...(types as any)); - } +/** + * Creates a type that is the left-to-right composition of the given types. + * If any of the types fails, the composition still continues with the failure passed on. + * @param types - Types to use. + */ +export function composeWithFailure<T extends ATC>(...types: T[]): ATCATCR<T>; +export function composeWithFailure<T extends KBAT>(...types: T[]): ATCBAT<T>; +export function composeWithFailure(...types: (AT | ATC)[]): ATC; +export function composeWithFailure(...types: (AT | ATC)[]): ATC { + return Argument.composeWithFailure(...(types as any)); +} - /** - * Checks if something is null, undefined, or a fail flag. - * @param value - Value to check. - */ - public static isFailure(value: any): value is null | undefined | (Flag & { value: any }) { - return Argument.isFailure(value); - } +/** + * Checks if something is null, undefined, or a fail flag. + * @param value - Value to check. + */ +export function isFailure(value: any): value is null | undefined | (Flag & { value: any }) { + return Argument.isFailure(value); +} - /** - * Creates a type from multiple types (product type). - * Only inputs where each type resolves with a non-void value are valid. - * @param types - Types to use. - */ - public static product<T extends ATC>(...types: T[]): ATCATCR<T>; - public static product<T extends KBAT>(...types: T[]): ATCBAT<T>; - public static product(...types: (AT | ATC)[]): ATC; - public static product(...types: (AT | ATC)[]): ATC { - return Argument.product(...(types as any)); - } +/** + * Creates a type from multiple types (product type). + * Only inputs where each type resolves with a non-void value are valid. + * @param types - Types to use. + */ +export function product<T extends ATC>(...types: T[]): ATCATCR<T>; +export function product<T extends KBAT>(...types: T[]): ATCBAT<T>; +export function product(...types: (AT | ATC)[]): ATC; +export function product(...types: (AT | ATC)[]): ATC { + return Argument.product(...(types as any)); +} - /** - * Creates a type where the parsed value must be within a range. - * @param type - The type to use. - * @param min - Minimum value. - * @param max - Maximum value. - * @param inclusive - Whether or not to be inclusive on the upper bound. - */ - public static range<T extends ATC>(type: T, min: number, max: number, inclusive?: boolean): ATCATCR<T>; - public static range<T extends KBAT>(type: T, min: number, max: number, inclusive?: boolean): ATCBAT<T>; - public static range(type: AT | ATC, min: number, max: number, inclusive?: boolean): ATC; - public static range(type: AT | ATC, min: number, max: number, inclusive?: boolean): ATC { - return Argument.range(type as any, min, max, inclusive); - } +/** + * Creates a type where the parsed value must be within a range. + * @param type - The type to use. + * @param min - Minimum value. + * @param max - Maximum value. + * @param inclusive - Whether or not to be inclusive on the upper bound. + */ +export function range<T extends ATC>(type: T, min: number, max: number, inclusive?: boolean): ATCATCR<T>; +export function range<T extends KBAT>(type: T, min: number, max: number, inclusive?: boolean): ATCBAT<T>; +export function range(type: AT | ATC, min: number, max: number, inclusive?: boolean): ATC; +export function range(type: AT | ATC, min: number, max: number, inclusive?: boolean): ATC { + return Argument.range(type as any, min, max, inclusive); +} - /** - * Creates a type that parses as normal but also tags it with some data. - * Result is in an object `{ tag, value }` and wrapped in `Flag.fail` when failed. - * @param type - The type to use. - * @param tag - Tag to add. Defaults to the `type` argument, so useful if it is a string. - */ - public static tagged<T extends ATC>(type: T, tag?: any): ATCATCR<T>; - public static tagged<T extends KBAT>(type: T, tag?: any): ATCBAT<T>; - public static tagged(type: AT | ATC, tag?: any): ATC; - public static tagged(type: AT | ATC, tag?: any): ATC { - return Argument.tagged(type as any, tag); - } +/** + * Creates a type that parses as normal but also tags it with some data. + * Result is in an object `{ tag, value }` and wrapped in `Flag.fail` when failed. + * @param type - The type to use. + * @param tag - Tag to add. Defaults to the `type` argument, so useful if it is a string. + */ +export function tagged<T extends ATC>(type: T, tag?: any): ATCATCR<T>; +export function tagged<T extends KBAT>(type: T, tag?: any): ATCBAT<T>; +export function tagged(type: AT | ATC, tag?: any): ATC; +export function tagged(type: AT | ATC, tag?: any): ATC { + return Argument.tagged(type as any, tag); +} - /** - * Creates a type from multiple types (union type). - * The first type that resolves to a non-void value is used. - * Each type will also be tagged using `tagged` with themselves. - * @param types - Types to use. - */ - public static taggedUnion<T extends ATC>(...types: T[]): ATCATCR<T>; - public static taggedUnion<T extends KBAT>(...types: T[]): ATCBAT<T>; - public static taggedUnion(...types: (AT | ATC)[]): ATC; - public static taggedUnion(...types: (AT | ATC)[]): ATC { - return Argument.taggedUnion(...(types as any)); - } +/** + * Creates a type from multiple types (union type). + * The first type that resolves to a non-void value is used. + * Each type will also be tagged using `tagged` with themselves. + * @param types - Types to use. + */ +export function taggedUnion<T extends ATC>(...types: T[]): ATCATCR<T>; +export function taggedUnion<T extends KBAT>(...types: T[]): ATCBAT<T>; +export function taggedUnion(...types: (AT | ATC)[]): ATC; +export function taggedUnion(...types: (AT | ATC)[]): ATC { + return Argument.taggedUnion(...(types as any)); +} - /** - * Creates a type that parses as normal but also tags it with some data and carries the original input. - * Result is in an object `{ tag, input, value }` and wrapped in `Flag.fail` when failed. - * @param type - The type to use. - * @param tag - Tag to add. Defaults to the `type` argument, so useful if it is a string. - */ - public static taggedWithInput<T extends ATC>(type: T, tag?: any): ATCATCR<T>; - public static taggedWithInput<T extends KBAT>(type: T, tag?: any): ATCBAT<T>; - public static taggedWithInput(type: AT | ATC, tag?: any): ATC; - public static taggedWithInput(type: AT | ATC, tag?: any): ATC { - return Argument.taggedWithInput(type as any, tag); - } +/** + * Creates a type that parses as normal but also tags it with some data and carries the original input. + * Result is in an object `{ tag, input, value }` and wrapped in `Flag.fail` when failed. + * @param type - The type to use. + * @param tag - Tag to add. Defaults to the `type` argument, so useful if it is a string. + */ +export function taggedWithInput<T extends ATC>(type: T, tag?: any): ATCATCR<T>; +export function taggedWithInput<T extends KBAT>(type: T, tag?: any): ATCBAT<T>; +export function taggedWithInput(type: AT | ATC, tag?: any): ATC; +export function taggedWithInput(type: AT | ATC, tag?: any): ATC { + return Argument.taggedWithInput(type as any, tag); +} - /** - * Creates a type from multiple types (union type). - * The first type that resolves to a non-void value is used. - * @param types - Types to use. - */ - public static union<T extends ATC>(...types: T[]): ATCATCR<T>; - public static union<T extends KBAT>(...types: T[]): ATCBAT<T>; - public static union(...types: (AT | ATC)[]): ATC; - public static union(...types: (AT | ATC)[]): ATC { - return Argument.union(...(types as any)); - } +/** + * Creates a type from multiple types (union type). + * The first type that resolves to a non-void value is used. + * @param types - Types to use. + */ +export function union<T extends ATC>(...types: T[]): ATCATCR<T>; +export function union<T extends KBAT>(...types: T[]): ATCBAT<T>; +export function union(...types: (AT | ATC)[]): ATC; +export function union(...types: (AT | ATC)[]): ATC { + return Argument.union(...(types as any)); +} - /** - * Creates a type with extra validation. - * If the predicate is not true, the value is considered invalid. - * @param type - The type to use. - * @param predicate - The predicate function. - */ - public static validate<T extends ATC>(type: T, predicate: ParsedValuePredicate): ATCATCR<T>; - public static validate<T extends KBAT>(type: T, predicate: ParsedValuePredicate): ATCBAT<T>; - public static validate(type: AT | ATC, predicate: ParsedValuePredicate): ATC; - public static validate(type: AT | ATC, predicate: ParsedValuePredicate): ATC { - return Argument.validate(type as any, predicate); - } +/** + * Creates a type with extra validation. + * If the predicate is not true, the value is considered invalid. + * @param type - The type to use. + * @param predicate - The predicate function. + */ +export function validate<T extends ATC>(type: T, predicate: ParsedValuePredicate): ATCATCR<T>; +export function validate<T extends KBAT>(type: T, predicate: ParsedValuePredicate): ATCBAT<T>; +export function validate(type: AT | ATC, predicate: ParsedValuePredicate): ATC; +export function validate(type: AT | ATC, predicate: ParsedValuePredicate): ATC { + return Argument.validate(type as any, predicate); +} - /** - * Creates a type that parses as normal but also carries the original input. - * Result is in an object `{ input, value }` and wrapped in `Flag.fail` when failed. - * @param type - The type to use. - */ - public static withInput<T extends ATC>(type: T): ATC<ATCR<T>>; - public static withInput<T extends KBAT>(type: T): ATCBAT<T>; - public static withInput(type: AT | ATC): ATC; - public static withInput(type: AT | ATC): ATC { - return Argument.withInput(type as any); - } +/** + * Creates a type that parses as normal but also carries the original input. + * Result is in an object `{ input, value }` and wrapped in `Flag.fail` when failed. + * @param type - The type to use. + */ +export function withInput<T extends ATC>(type: T): ATC<ATCR<T>>; +export function withInput<T extends KBAT>(type: T): ATCBAT<T>; +export function withInput(type: AT | ATC): ATC; +export function withInput(type: AT | ATC): ATC { + return Argument.withInput(type as any); } type BushArgumentTypeCasterReturn<R> = R extends BushArgumentTypeCaster<infer S> ? S : R; diff --git a/src/lib/common/util/Format.ts b/src/lib/common/util/Format.ts index 6cb6edc..260a0be 100644 --- a/src/lib/common/util/Format.ts +++ b/src/lib/common/util/Format.ts @@ -1,107 +1,112 @@ import { type CodeBlockLang } from '#lib'; -import { EscapeMarkdownOptions, Formatters, Util } from 'discord.js'; +import { + escapeBold, + escapeCodeBlock, + escapeInlineCode, + escapeItalic, + EscapeMarkdownOptions, + escapeSpoiler, + escapeStrikethrough, + escapeUnderline, + Formatters +} from 'discord.js'; /** - * Formats and escapes content for formatting + * Wraps the content inside a codeblock with no language. + * @param content The content to wrap. */ -export class Format { - /** - * Wraps the content inside a codeblock with no language. - * @param content The content to wrap. - */ - public static codeBlock(content: string): string; +export function codeBlock(content: string): string; - /** - * Wraps the content inside a codeblock with the specified language. - * @param language The language for the codeblock. - * @param content The content to wrap. - */ - public static codeBlock(language: CodeBlockLang, content: string): string; - public static codeBlock(languageOrContent: string, content?: string): string { - return typeof content === 'undefined' - ? Formatters.codeBlock(Util.escapeCodeBlock(`${languageOrContent}`)) - : Formatters.codeBlock(`${languageOrContent}`, Util.escapeCodeBlock(`${content}`)); - } +/** + * Wraps the content inside a codeblock with the specified language. + * @param language The language for the codeblock. + * @param content The content to wrap. + */ +export function codeBlock(language: CodeBlockLang, content: string): string; +export function codeBlock(languageOrContent: string, content?: string): string { + return typeof content === 'undefined' + ? Formatters.codeBlock(escapeCodeBlock(`${languageOrContent}`)) + : Formatters.codeBlock(`${languageOrContent}`, escapeCodeBlock(`${content}`)); +} - /** - * Wraps the content inside \`backticks\`, which formats it as inline code. - * @param content The content to wrap. - */ - public static inlineCode(content: string): string { - return Formatters.inlineCode(Util.escapeInlineCode(`${content}`)); - } +/** + * Wraps the content inside \`backticks\`, which formats it as inline code. + * @param content The content to wrap. + */ +export function inlineCode(content: string): string { + return Formatters.inlineCode(escapeInlineCode(`${content}`)); +} - /** - * Formats the content into italic text. - * @param content The content to wrap. - */ - public static italic(content: string): string { - return Formatters.italic(Util.escapeItalic(`${content}`)); - } +/** + * Formats the content into italic text. + * @param content The content to wrap. + */ +export function italic(content: string): string { + return Formatters.italic(escapeItalic(`${content}`)); +} - /** - * Formats the content into bold text. - * @param content The content to wrap. - */ - public static bold(content: string): string { - return Formatters.bold(Util.escapeBold(`${content}`)); - } +/** + * Formats the content into bold text. + * @param content The content to wrap. + */ +export function bold(content: string): string { + return Formatters.bold(escapeBold(`${content}`)); +} - /** - * Formats the content into underscored text. - * @param content The content to wrap. - */ - public static underscore(content: string): string { - return Formatters.underscore(Util.escapeUnderline(`${content}`)); - } +/** + * Formats the content into underscored text. + * @param content The content to wrap. + */ +export function underscore(content: string): string { + return Formatters.underscore(escapeUnderline(`${content}`)); +} - /** - * Formats the content into strike-through text. - * @param content The content to wrap. - */ - public static strikethrough(content: string): string { - return Formatters.strikethrough(Util.escapeStrikethrough(`${content}`)); - } +/** + * Formats the content into strike-through text. + * @param content The content to wrap. + */ +export function strikethrough(content: string): string { + return Formatters.strikethrough(escapeStrikethrough(`${content}`)); +} - /** - * Wraps the content inside spoiler (hidden text). - * @param content The content to wrap. - */ - public static spoiler(content: string): string { - return Formatters.spoiler(Util.escapeSpoiler(`${content}`)); - } +/** + * Wraps the content inside spoiler (hidden text). + * @param content The content to wrap. + */ +export function spoiler(content: string): string { + return Formatters.spoiler(escapeSpoiler(`${content}`)); +} - /** - * Escapes any Discord-flavour markdown in a string. - * @param text Content to escape - * @param options Options for escaping the markdown - */ - public static escapeMarkdown(text: string, options?: EscapeMarkdownOptions): string { - return Util.escapeMarkdown(`${text}`, options); - } +/** + * Escapes any Discord-flavour markdown in a string. + * @param text Content to escape + * @param options Options for escaping the markdown + */ +export function escapeMarkdown(text: string, options?: EscapeMarkdownOptions): string { + return escapeMarkdown(`${text}`, options); +} - /** - * Formats input: makes it bold and escapes any other markdown - * @param text The input - */ - public static input(text: string): string { - return this.bold(this.escapeMarkdown(this.sanitizeWtlAndControl(`${text}`))); - } +/** + * Formats input: makes it bold and escapes any other markdown + * @param text The input + */ +export function input(text: string): string { + return bold(escapeMarkdown(sanitizeWtlAndControl(`${text}`))); +} - /** - * Formats input for logs: makes it highlighted - * @param text The input - */ - public static inputLog(text: string): string { - return `<<${this.sanitizeWtlAndControl(`${text}`)}>>`; - } +/** + * Formats input for logs: makes it highlighted + * @param text The input + */ +export function inputLog(text: string): string { + return `<<${sanitizeWtlAndControl(`${text}`)}>>`; +} - /** - * Removes all characters in a string that are either control characters or change the direction of text etc. - * @param str The string you would like sanitized - */ - public static sanitizeWtlAndControl(str: string) { - // eslint-disable-next-line no-control-regex - return `${str}`.replace(/[\u0000-\u001F\u007F-\u009F\u200B]/g, ''); - } +/** + * Removes all characters in a string that are either control characters or change the direction of text etc. + * @param str The string you would like sanitized + */ +export function sanitizeWtlAndControl(str: string) { + // eslint-disable-next-line no-control-regex + return `${str}`.replace(/[\u0000-\u001F\u007F-\u009F\u200B]/g, ''); } diff --git a/src/lib/common/util/Moderation.ts b/src/lib/common/util/Moderation.ts index 6cdc141..a08dfa4 100644 --- a/src/lib/common/util/Moderation.ts +++ b/src/lib/common/util/Moderation.ts @@ -1,4 +1,16 @@ -import { ActivePunishment, ActivePunishmentType, Guild as GuildDB, ModLog, type ModLogType } from '#lib'; +import { + ActivePunishment, + ActivePunishmentType, + colors, + emojis, + format, + Guild as GuildDB, + handleError, + humanizeDuration, + ModLog, + resolveNonCachedUser, + type ModLogType +} from '#lib'; import assert from 'assert'; import { ActionRowBuilder, @@ -40,275 +52,270 @@ enum reversedPunishMap { } /** - * A utility class with moderation-related methods. + * Checks if a moderator can perform a moderation action on another user. |
