Files
discordeno/plugins/validations/src/components.ts
LTS20050703 cd5915c8b6 add new select menu components (#2583)
* add new select menu components

* fix: check for component type
2022-11-14 12:34:41 -06:00

236 lines
7.3 KiB
TypeScript

import { Bot, ButtonStyles, Emoji, MessageComponents, MessageComponentTypes } from "../deps.ts";
export function validateComponents(bot: Bot, components: MessageComponents) {
if (!components?.length) return;
let actionRowCounter = 0;
for (const component of components) {
actionRowCounter++;
// Max of 5 ActionRows per message
if (actionRowCounter > 5) throw new Error("Too many action rows.");
// Max of 5 Buttons (or any component type) within an ActionRow
if (component.components?.length > 5) throw new Error("Too many components.");
else if (
component.components?.length > 1 &&
component.components.some((subComponent) =>
subComponent.type === MessageComponentTypes.SelectMenu ||
subComponent.type === MessageComponentTypes.SelectMenuChannels ||
subComponent.type === MessageComponentTypes.SelectMenuRoles ||
subComponent.type === MessageComponentTypes.SelectMenuUsers ||
subComponent.type === MessageComponentTypes.SelectMenuUsersAndRoles
)
) {
throw new Error("Select component must be alone.");
}
for (const subComponent of component.components) {
if (
subComponent.customId &&
!bot.utils.validateLength(subComponent.customId, { max: 100 })
) {
throw new Error("The custom id in the component is too big.");
}
// 5 Link buttons can not have a customId
if (subComponent.type === MessageComponentTypes.Button) {
if (subComponent.style === ButtonStyles.Link && subComponent.customId) {
throw new Error("Link buttons can not have custom ids.");
}
// Other buttons must have a customId
if (
!subComponent.customId && subComponent.style !== ButtonStyles.Link
) {
throw new Error(
"The button requires a custom id if it is not a link button.",
);
}
if (!bot.utils.validateLength(subComponent.label, { max: 80 })) {
throw new Error("The label can not be longer than 80 characters.");
}
subComponent.emoji = makeEmojiFromString(subComponent.emoji);
}
if (
subComponent.type === MessageComponentTypes.SelectMenu ||
subComponent.type === MessageComponentTypes.SelectMenuChannels ||
subComponent.type === MessageComponentTypes.SelectMenuRoles ||
subComponent.type === MessageComponentTypes.SelectMenuUsers ||
subComponent.type === MessageComponentTypes.SelectMenuUsersAndRoles
) {
if (
subComponent.placeholder &&
!bot.utils.validateLength(subComponent.placeholder, { max: 150 })
) {
throw new Error(
"The component placeholder can not be longer than 150 characters.",
);
}
if (subComponent.minValues) {
if (subComponent.minValues < 1) {
throw new Error(
"The min values must be more than 1 in a select component.",
);
}
if (subComponent.minValues > 25) {
throw new Error(
"The min values must be less than 25 in a select component.",
);
}
if (!subComponent.maxValues) subComponent.maxValues = subComponent.minValues;
if (subComponent.minValues > subComponent.maxValues) {
throw new Error(
"The select component can not have a min values higher than a max values.",
);
}
}
if (subComponent.maxValues) {
if (subComponent.maxValues < 1) {
throw new Error(
"The max values must be more than 1 in a select component.",
);
}
if (subComponent.maxValues > 25) {
throw new Error(
"The max values must be less than 25 in a select component.",
);
}
}
if (subComponent.type === MessageComponentTypes.SelectMenu) {
if (subComponent.options.length < 1) throw new Error("You need at least 1 option in the select component.");
if (subComponent.options.length > 25) {
throw new Error(
"You can not have more than 25 options in the select component.",
);
}
let defaults = 0;
for (const option of subComponent.options) {
if (option.default) {
defaults++;
if (defaults > (subComponent.maxValues || 25)) throw new Error("You chose too many default options.");
}
if (!bot.utils.validateLength(option.label, { max: 25 })) {
throw new Error(
"The select component label can not exceed 25 characters.",
);
}
if (!bot.utils.validateLength(option.value, { max: 100 })) {
throw new Error(
"The select component value can not exceed 100 characters.",
);
}
if (
option.description &&
!bot.utils.validateLength(option.description, { max: 50 })
) {
throw new Error(
"The select option description can not exceed 50 characters.",
);
}
option.emoji = makeEmojiFromString(option.emoji);
}
}
}
if (subComponent.type === MessageComponentTypes.InputText) {
// Other buttons must have a customId
if (
!subComponent.customId
) {
throw new Error(
"The text input requires a custom id",
);
}
if (!bot.utils.validateLength(subComponent.label, { max: 45 })) {
throw new Error("The label can not be longer than 45 characters.");
}
if (subComponent.minLength) {
if (subComponent.minLength < 0) {
throw new Error(
"The min length must be more than 0 in a text input component.",
);
}
if (subComponent.minLength > 4000) {
throw new Error(
"The min length must be less than 4000 in a text input component.",
);
}
if (subComponent.maxLength && subComponent.minLength > subComponent.maxLength) {
throw new Error(
"The text input component can not have a higher min length than the max length.",
);
}
}
if (subComponent.maxLength) {
if (subComponent.maxLength < 1) {
throw new Error(
"The max length must be more than 1 in a text input component.",
);
}
if (subComponent.maxLength > 4000) {
throw new Error(
"The max length must be less than 4000 in a text input component.",
);
}
}
}
}
}
}
function makeEmojiFromString(
emoji?:
| string
| {
id?: string | bigint | undefined;
name?: string | undefined;
animated?: boolean | undefined;
},
) {
if (!emoji) return;
if (typeof emoji !== "string") {
return {
id: emoji.id ? BigInt(emoji.id) : undefined,
name: emoji.name,
animated: emoji.animated,
};
}
// A snowflake id was provided
if (/^[0-9]+$/.test(emoji)) {
emoji = {
id: BigInt(emoji),
};
} else {
// A unicode emoji was provided
emoji = {
name: emoji,
};
}
return emoji as Emoji;
}