mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-09 16:13:31 +01:00
336 lines
7.1 KiB
TypeScript
336 lines
7.1 KiB
TypeScript
import type {
|
|
APIEmbed,
|
|
APIEmbedAuthor,
|
|
APIEmbedField,
|
|
APIEmbedFooter,
|
|
APIEmbedImage,
|
|
APIEmbedProvider,
|
|
APIEmbedThumbnail,
|
|
APIEmbedVideo,
|
|
} from 'discord-api-types/v9';
|
|
import {
|
|
authorNamePredicate,
|
|
colorPredicate,
|
|
descriptionPredicate,
|
|
embedFieldsArrayPredicate,
|
|
fieldInlinePredicate,
|
|
fieldNamePredicate,
|
|
fieldValuePredicate,
|
|
footerTextPredicate,
|
|
timestampPredicate,
|
|
titlePredicate,
|
|
urlPredicate,
|
|
validateFieldLength,
|
|
} from './Assertions';
|
|
|
|
export interface AuthorOptions {
|
|
name: string;
|
|
url?: string;
|
|
iconURL?: string;
|
|
}
|
|
|
|
export interface FooterOptions {
|
|
text: string;
|
|
iconURL?: string;
|
|
}
|
|
|
|
/**
|
|
* Represents an embed in a message (image/video preview, rich embed, etc.)
|
|
*/
|
|
export class Embed implements APIEmbed {
|
|
/**
|
|
* An array of fields of this embed
|
|
*/
|
|
public readonly fields: APIEmbedField[];
|
|
|
|
/**
|
|
* The embed title
|
|
*/
|
|
public readonly title?: string;
|
|
|
|
/**
|
|
* The embed description
|
|
*/
|
|
public readonly description?: string;
|
|
|
|
/**
|
|
* The embed url
|
|
*/
|
|
public readonly url?: string;
|
|
|
|
/**
|
|
* The embed color
|
|
*/
|
|
public readonly color?: number;
|
|
|
|
/**
|
|
* The timestamp of the embed in the ISO format
|
|
*/
|
|
public readonly timestamp?: string;
|
|
|
|
/**
|
|
* The embed thumbnail data
|
|
*/
|
|
public readonly thumbnail?: APIEmbedThumbnail;
|
|
|
|
/**
|
|
* The embed image data
|
|
*/
|
|
public readonly image?: APIEmbedImage;
|
|
|
|
/**
|
|
* Received video data
|
|
*/
|
|
public readonly video?: APIEmbedVideo;
|
|
|
|
/**
|
|
* The embed author data
|
|
*/
|
|
public readonly author?: APIEmbedAuthor;
|
|
|
|
/**
|
|
* Received data about the embed provider
|
|
*/
|
|
public readonly provider?: APIEmbedProvider;
|
|
|
|
/**
|
|
* The embed footer data
|
|
*/
|
|
public readonly footer?: APIEmbedFooter;
|
|
|
|
public constructor(data: APIEmbed = {}) {
|
|
this.title = data.title;
|
|
this.description = data.description;
|
|
this.url = data.url;
|
|
this.color = data.color;
|
|
this.thumbnail = data.thumbnail;
|
|
this.image = data.image;
|
|
this.video = data.video;
|
|
this.author = data.author;
|
|
this.provider = data.provider;
|
|
this.footer = data.footer;
|
|
this.fields = data.fields ?? [];
|
|
|
|
if (data.timestamp) this.timestamp = new Date(data.timestamp).toISOString();
|
|
}
|
|
|
|
/**
|
|
* The accumulated length for the embed title, description, fields, footer text, and author name
|
|
*/
|
|
public get length(): number {
|
|
return (
|
|
(this.title?.length ?? 0) +
|
|
(this.description?.length ?? 0) +
|
|
this.fields.reduce((prev, curr) => prev + curr.name.length + curr.value.length, 0) +
|
|
(this.footer?.text.length ?? 0) +
|
|
(this.author?.name.length ?? 0)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Adds a field to the embed (max 25)
|
|
*
|
|
* @param field The field to add.
|
|
*/
|
|
public addField(field: APIEmbedField): this {
|
|
return this.addFields(field);
|
|
}
|
|
|
|
/**
|
|
* Adds fields to the embed (max 25)
|
|
*
|
|
* @param fields The fields to add
|
|
*/
|
|
public addFields(...fields: APIEmbedField[]): this {
|
|
// Data assertions
|
|
embedFieldsArrayPredicate.parse(fields);
|
|
|
|
// Ensure adding these fields won't exceed the 25 field limit
|
|
validateFieldLength(this.fields, fields.length);
|
|
|
|
this.fields.push(...Embed.normalizeFields(...fields));
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Removes, replaces, or inserts fields in the embed (max 25)
|
|
*
|
|
* @param index The index to start at
|
|
* @param deleteCount The number of fields to remove
|
|
* @param fields The replacing field objects
|
|
*/
|
|
public spliceFields(index: number, deleteCount: number, ...fields: APIEmbedField[]): this {
|
|
// Data assertions
|
|
embedFieldsArrayPredicate.parse(fields);
|
|
|
|
// Ensure adding these fields won't exceed the 25 field limit
|
|
validateFieldLength(this.fields, fields.length - deleteCount);
|
|
|
|
this.fields.splice(index, deleteCount, ...Embed.normalizeFields(...fields));
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets the embed's fields (max 25).
|
|
* @param fields The fields to set
|
|
*/
|
|
public setFields(...fields: APIEmbedField[]) {
|
|
this.spliceFields(0, this.fields.length, ...fields);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets the author of this embed
|
|
*
|
|
* @param options The options for the author
|
|
*/
|
|
public setAuthor(options: AuthorOptions | null): this {
|
|
if (options === null) {
|
|
Reflect.set(this, 'author', undefined);
|
|
return this;
|
|
}
|
|
|
|
const { name, iconURL, url } = options;
|
|
// Data assertions
|
|
authorNamePredicate.parse(name);
|
|
urlPredicate.parse(iconURL);
|
|
urlPredicate.parse(url);
|
|
|
|
Reflect.set(this, 'author', { name, url, icon_url: iconURL });
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets the color of this embed
|
|
*
|
|
* @param color The color of the embed
|
|
*/
|
|
public setColor(color: number | null): this {
|
|
// Data assertions
|
|
colorPredicate.parse(color);
|
|
|
|
Reflect.set(this, 'color', color ?? undefined);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets the description of this embed
|
|
*
|
|
* @param description The description
|
|
*/
|
|
public setDescription(description: string | null): this {
|
|
// Data assertions
|
|
descriptionPredicate.parse(description);
|
|
|
|
Reflect.set(this, 'description', description ?? undefined);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets the footer of this embed
|
|
*
|
|
* @param options The options for the footer
|
|
*/
|
|
public setFooter(options: FooterOptions | null): this {
|
|
if (options === null) {
|
|
Reflect.set(this, 'footer', undefined);
|
|
return this;
|
|
}
|
|
|
|
const { text, iconURL } = options;
|
|
// Data assertions
|
|
footerTextPredicate.parse(text);
|
|
urlPredicate.parse(iconURL);
|
|
|
|
Reflect.set(this, 'footer', { text, icon_url: iconURL });
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets the image of this embed
|
|
*
|
|
* @param url The URL of the image
|
|
*/
|
|
public setImage(url: string | null): this {
|
|
// Data assertions
|
|
urlPredicate.parse(url);
|
|
|
|
Reflect.set(this, 'image', url ? { url } : undefined);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets the thumbnail of this embed
|
|
*
|
|
* @param url The URL of the thumbnail
|
|
*/
|
|
public setThumbnail(url: string | null): this {
|
|
// Data assertions
|
|
urlPredicate.parse(url);
|
|
|
|
Reflect.set(this, 'thumbnail', url ? { url } : undefined);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets the timestamp of this embed
|
|
*
|
|
* @param timestamp The timestamp or date
|
|
*/
|
|
public setTimestamp(timestamp: number | Date | null = Date.now()): this {
|
|
// Data assertions
|
|
timestampPredicate.parse(timestamp);
|
|
|
|
Reflect.set(this, 'timestamp', timestamp ? new Date(timestamp).toISOString() : undefined);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets the title of this embed
|
|
*
|
|
* @param title The title
|
|
*/
|
|
public setTitle(title: string | null): this {
|
|
// Data assertions
|
|
titlePredicate.parse(title);
|
|
|
|
Reflect.set(this, 'title', title ?? undefined);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets the URL of this embed
|
|
*
|
|
* @param url The URL
|
|
*/
|
|
public setURL(url: string | null): this {
|
|
// Data assertions
|
|
urlPredicate.parse(url);
|
|
|
|
Reflect.set(this, 'url', url ?? undefined);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Transforms the embed to a plain object
|
|
*/
|
|
public toJSON(): APIEmbed {
|
|
return { ...this };
|
|
}
|
|
|
|
/**
|
|
* Normalizes field input and resolves strings
|
|
*
|
|
* @param fields Fields to normalize
|
|
*/
|
|
public static normalizeFields(...fields: APIEmbedField[]): APIEmbedField[] {
|
|
return fields.flat(Infinity).map((field) => {
|
|
fieldNamePredicate.parse(field.name);
|
|
fieldValuePredicate.parse(field.value);
|
|
fieldInlinePredicate.parse(field.inline);
|
|
|
|
return { name: field.name, value: field.value, inline: field.inline ?? undefined };
|
|
});
|
|
}
|
|
}
|