mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-18 20:43:30 +01:00
refactor: builders (#10448)
BREAKING CHANGE: formatters export removed (prev. deprecated) BREAKING CHANGE: `SelectMenuBuilder` and `SelectMenuOptionBuilder` have been removed (prev. deprecated) BREAKING CHANGE: `EmbedBuilder` no longer takes camalCase options BREAKING CHANGE: `ActionRowBuilder` now has specialized `[add/set]X` methods as opposed to the current `[add/set]Components` BREAKING CHANGE: Removed `equals` methods BREAKING CHANGE: Sapphire -> zod for validation BREAKING CHANGE: Removed the ability to pass `null`/`undefined` to clear fields, use `clearX()` instead BREAKING CHANGE: Renamed all "slash command" symbols to instead use "chat input command" BREAKING CHANGE: Removed `ContextMenuCommandBuilder` in favor of `MessageCommandBuilder` and `UserCommandBuilder` BREAKING CHANGE: Removed support for passing the "string key"s of enums BREAKING CHANGE: Removed `Button` class in favor for specialized classes depending on the style BREAKING CHANGE: Removed nested `addX` styled-methods in favor of plural `addXs` Co-authored-by: Vlad Frangu <me@vladfrangu.dev> Co-authored-by: Almeida <github@almeidx.dev>
This commit is contained in:
@@ -1,99 +1,70 @@
|
||||
import { s } from '@sapphire/shapeshift';
|
||||
import type { APIEmbedField } from 'discord-api-types/v10';
|
||||
import { isValidationEnabled } from '../../util/validation.js';
|
||||
import { z } from 'zod';
|
||||
import { refineURLPredicate } from '../../Assertions.js';
|
||||
import { embedLength } from '../../util/componentUtil.js';
|
||||
|
||||
export const fieldNamePredicate = s
|
||||
const namePredicate = z.string().min(1).max(256);
|
||||
|
||||
const iconURLPredicate = z
|
||||
.string()
|
||||
.lengthGreaterThanOrEqual(1)
|
||||
.lengthLessThanOrEqual(256)
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
.url()
|
||||
.refine(refineURLPredicate(['http:', 'https:', 'attachment:']), {
|
||||
message: 'Invalid protocol for icon URL. Must be http:, https:, or attachment:',
|
||||
});
|
||||
|
||||
export const fieldValuePredicate = s
|
||||
const URLPredicate = z
|
||||
.string()
|
||||
.lengthGreaterThanOrEqual(1)
|
||||
.lengthLessThanOrEqual(1_024)
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
.url()
|
||||
.refine(refineURLPredicate(['http:', 'https:']), { message: 'Invalid protocol for URL. Must be http: or https:' });
|
||||
|
||||
export const fieldInlinePredicate = s.boolean().optional();
|
||||
export const embedFieldPredicate = z.object({
|
||||
name: namePredicate,
|
||||
value: z.string().min(1).max(1_024),
|
||||
inline: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export const embedFieldPredicate = s
|
||||
export const embedAuthorPredicate = z.object({
|
||||
name: namePredicate,
|
||||
icon_url: iconURLPredicate.optional(),
|
||||
url: URLPredicate.optional(),
|
||||
});
|
||||
|
||||
export const embedFooterPredicate = z.object({
|
||||
text: z.string().min(1).max(2_048),
|
||||
icon_url: iconURLPredicate.optional(),
|
||||
});
|
||||
|
||||
export const embedPredicate = z
|
||||
.object({
|
||||
name: fieldNamePredicate,
|
||||
value: fieldValuePredicate,
|
||||
inline: fieldInlinePredicate,
|
||||
title: namePredicate.optional(),
|
||||
description: z.string().min(1).max(4_096).optional(),
|
||||
url: URLPredicate.optional(),
|
||||
timestamp: z.string().optional(),
|
||||
color: z.number().int().min(0).max(0xffffff).optional(),
|
||||
footer: embedFooterPredicate.optional(),
|
||||
image: z.object({ url: URLPredicate }).optional(),
|
||||
thumbnail: z.object({ url: URLPredicate }).optional(),
|
||||
author: embedAuthorPredicate.optional(),
|
||||
fields: z.array(embedFieldPredicate).max(25).optional(),
|
||||
})
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const embedFieldsArrayPredicate = embedFieldPredicate.array().setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const fieldLengthPredicate = s.number().lessThanOrEqual(25).setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export function validateFieldLength(amountAdding: number, fields?: APIEmbedField[]): void {
|
||||
fieldLengthPredicate.parse((fields?.length ?? 0) + amountAdding);
|
||||
}
|
||||
|
||||
export const authorNamePredicate = fieldNamePredicate.nullable().setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const imageURLPredicate = s
|
||||
.string()
|
||||
.url({
|
||||
allowedProtocols: ['http:', 'https:', 'attachment:'],
|
||||
})
|
||||
.nullish()
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const urlPredicate = s
|
||||
.string()
|
||||
.url({
|
||||
allowedProtocols: ['http:', 'https:'],
|
||||
})
|
||||
.nullish()
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const embedAuthorPredicate = s
|
||||
.object({
|
||||
name: authorNamePredicate,
|
||||
iconURL: imageURLPredicate,
|
||||
url: urlPredicate,
|
||||
})
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const RGBPredicate = s
|
||||
.number()
|
||||
.int()
|
||||
.greaterThanOrEqual(0)
|
||||
.lessThanOrEqual(255)
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
export const colorPredicate = s
|
||||
.number()
|
||||
.int()
|
||||
.greaterThanOrEqual(0)
|
||||
.lessThanOrEqual(0xffffff)
|
||||
.or(s.tuple([RGBPredicate, RGBPredicate, RGBPredicate]))
|
||||
.nullable()
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const descriptionPredicate = s
|
||||
.string()
|
||||
.lengthGreaterThanOrEqual(1)
|
||||
.lengthLessThanOrEqual(4_096)
|
||||
.nullable()
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const footerTextPredicate = s
|
||||
.string()
|
||||
.lengthGreaterThanOrEqual(1)
|
||||
.lengthLessThanOrEqual(2_048)
|
||||
.nullable()
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const embedFooterPredicate = s
|
||||
.object({
|
||||
text: footerTextPredicate,
|
||||
iconURL: imageURLPredicate,
|
||||
})
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const timestampPredicate = s.union([s.number(), s.date()]).nullable().setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const titlePredicate = fieldNamePredicate.nullable().setValidationEnabled(isValidationEnabled);
|
||||
.refine(
|
||||
(embed) => {
|
||||
return (
|
||||
embed.title !== undefined ||
|
||||
embed.description !== undefined ||
|
||||
(embed.fields !== undefined && embed.fields.length > 0) ||
|
||||
embed.footer !== undefined ||
|
||||
embed.author !== undefined ||
|
||||
embed.image !== undefined ||
|
||||
embed.thumbnail !== undefined
|
||||
);
|
||||
},
|
||||
{
|
||||
message: 'Embed must have at least a title, description, a field, a footer, an author, an image, OR a thumbnail.',
|
||||
},
|
||||
)
|
||||
.refine(
|
||||
(embed) => {
|
||||
return embedLength(embed) <= 6_000;
|
||||
},
|
||||
{ message: 'Embeds must not exceed 6000 characters in total.' },
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user