mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-09 16:13:31 +01:00
feat(RichEmbed): backport spliceFields and normalizeField (#3762)
* backport: RichEmbed#checkField, Util#resolveString * backport: RichEmbed#spliceFields * fix: typo * chore: use util.resolveString everywhere * chore: rename EmbedFIeld to EmbedFieldData * consistency with v12 * chore: rename checkField to normalizeField * consistency with v12 * fix: EmbedField instead of EmbedFieldData * fix(typings): EmbedFIeld#inline is guaranteed * fix(docs): add JSDocs typedef for EmbedFieldData * fix(typings): EmbedFIeldData#name/#value * should be StringResolvable * refactor(RichEmbed): do not duplicate field prop checking * docs(RichEmbed): document default for inline * fix(RichEmbed): pass correct parameters to normalizeField * typings(RichEmbed): add missing spaces Co-authored-by: SpaceEEC <spaceeec@yahoo.com>
This commit is contained in:
@@ -26,6 +26,7 @@ module.exports = {
|
||||
// Shortcuts to Util methods
|
||||
escapeMarkdown: Util.escapeMarkdown,
|
||||
fetchRecommendedShards: Util.fetchRecommendedShards,
|
||||
resolveString: Util.resolveString,
|
||||
splitMessage: Util.splitMessage,
|
||||
|
||||
// Structures
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const Attachment = require('./Attachment');
|
||||
const MessageEmbed = require('./MessageEmbed');
|
||||
const util = require('../util/Util');
|
||||
let ClientDataResolver;
|
||||
|
||||
/**
|
||||
@@ -87,7 +88,7 @@ class RichEmbed {
|
||||
* @returns {RichEmbed} This embed
|
||||
*/
|
||||
setTitle(title) {
|
||||
title = resolveString(title);
|
||||
title = util.resolveString(title);
|
||||
if (title.length > 256) throw new RangeError('RichEmbed titles may not exceed 256 characters.');
|
||||
this.title = title;
|
||||
return this;
|
||||
@@ -99,7 +100,7 @@ class RichEmbed {
|
||||
* @returns {RichEmbed} This embed
|
||||
*/
|
||||
setDescription(description) {
|
||||
description = resolveString(description);
|
||||
description = util.resolveString(description);
|
||||
if (description.length > 2048) throw new RangeError('RichEmbed descriptions may not exceed 2048 characters.');
|
||||
this.description = description;
|
||||
return this;
|
||||
@@ -134,7 +135,7 @@ class RichEmbed {
|
||||
* @returns {RichEmbed} This embed
|
||||
*/
|
||||
setAuthor(name, icon, url) {
|
||||
this.author = { name: resolveString(name), icon_url: icon, url };
|
||||
this.author = { name: util.resolveString(name), icon_url: icon, url };
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -158,13 +159,7 @@ class RichEmbed {
|
||||
*/
|
||||
addField(name, value, inline = false) {
|
||||
if (this.fields.length >= 25) throw new RangeError('RichEmbeds may not exceed 25 fields.');
|
||||
name = resolveString(name);
|
||||
if (name.length > 256) throw new RangeError('RichEmbed field names may not exceed 256 characters.');
|
||||
if (!/\S/.test(name)) throw new RangeError('RichEmbed field names may not be empty.');
|
||||
value = resolveString(value);
|
||||
if (value.length > 1024) throw new RangeError('RichEmbed field values may not exceed 1024 characters.');
|
||||
if (!/\S/.test(value)) throw new RangeError('RichEmbed field values may not be empty.');
|
||||
this.fields.push({ name, value, inline });
|
||||
this.fields.push(this.constructor.normalizeField(name, value, inline));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -177,6 +172,37 @@ class RichEmbed {
|
||||
return this.addField('\u200B', '\u200B', inline);
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} EmbedField
|
||||
* @property {string} name The name of this field
|
||||
* @property {string} value The value of this field
|
||||
* @property {boolean} inline If this field will be displayed inline
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} EmbedFieldData
|
||||
* @property {StringResolvable} name The name of this field
|
||||
* @property {StringResolvable} value The value of this field
|
||||
* @property {boolean} [inline=false] If this field will be displayed inline
|
||||
*/
|
||||
|
||||
/**
|
||||
* Removes, replaces, and inserts fields in the embed (max 25).
|
||||
* @param {number} index The index to start at
|
||||
* @param {number} deleteCount The number of fields to remove
|
||||
* @param {...EmbedFieldData} [fields] The replacing field objects
|
||||
* @returns {RichEmbed}
|
||||
*/
|
||||
spliceFields(index, deleteCount, ...fields) {
|
||||
if (fields) {
|
||||
const mapper = ({ name, value, inline }) => this.constructor.normalizeField(name, value, inline);
|
||||
this.fields.splice(index, deleteCount, ...fields.map(mapper));
|
||||
} else {
|
||||
this.fields.splice(index, deleteCount);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the thumbnail of this embed.
|
||||
* @param {string} url The URL of the thumbnail
|
||||
@@ -204,7 +230,7 @@ class RichEmbed {
|
||||
* @returns {RichEmbed} This embed
|
||||
*/
|
||||
setFooter(text, icon) {
|
||||
text = resolveString(text);
|
||||
text = util.resolveString(text);
|
||||
if (text.length > 2048) throw new RangeError('RichEmbed footer text may not exceed 2048 characters.');
|
||||
this.footer = { text, icon_url: icon };
|
||||
return this;
|
||||
@@ -284,12 +310,23 @@ class RichEmbed {
|
||||
} : null,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes field input and resolves strings.
|
||||
* @param {StringResolvable} name The name of the field
|
||||
* @param {StringResolvable} value The value of the field
|
||||
* @param {boolean} [inline=false] Set the field to display inline
|
||||
* @returns {EmbedField}
|
||||
*/
|
||||
static normalizeField(name, value, inline = false) {
|
||||
name = util.resolveString(name);
|
||||
if (name.length > 256) throw new RangeError('RichEmbed field names may not exceed 256 characters.');
|
||||
if (!/\S/.test(name)) throw new RangeError('RichEmbed field names may not be empty.');
|
||||
value = util.resolveString(value);
|
||||
if (value.length > 1024) throw new RangeError('RichEmbed field values may not exceed 1024 characters.');
|
||||
if (!/\S/.test(value)) throw new RangeError('RichEmbed field values may not be empty.');
|
||||
return { name, value, inline };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RichEmbed;
|
||||
|
||||
function resolveString(data) {
|
||||
if (typeof data === 'string') return data;
|
||||
if (data instanceof Array) return data.join('\n');
|
||||
return String(data);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,25 @@ class Util {
|
||||
return messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data that can be resolved to give a string. This can be:
|
||||
* * A string
|
||||
* * An array (joined with a new line delimiter to give a string)
|
||||
* * Any value
|
||||
* @typedef {string|Array|*} StringResolvable
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resolves a StringResolvable to a string.
|
||||
* @param {StringResolvable} data The string resolvable to resolve
|
||||
* @returns {string}
|
||||
*/
|
||||
static resolveString(data) {
|
||||
if (typeof data === 'string') return data;
|
||||
if (Array.isArray(data)) return data.join('\n');
|
||||
return String(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes any Discord-flavour markdown in a string.
|
||||
* @param {string} text Content to escape
|
||||
|
||||
15
typings/index.d.ts
vendored
15
typings/index.d.ts
vendored
@@ -234,6 +234,7 @@ declare module 'discord.js' {
|
||||
public resolveChannel(channel: ChannelResolvable): Channel;
|
||||
public resolveChannelID(channel: ChannelResolvable): Snowflake;
|
||||
public resolveColor(color: ColorResolvable): number;
|
||||
public resolveString(data: StringResolvable): string;
|
||||
public resolveEmojiIdentifier(emoji: EmojiIdentifierResolvable): string;
|
||||
public resolveFile(resource: BufferResolvable | Stream): Promise<Buffer>;
|
||||
public resolveGuild(guild: GuildResolvable): Guild;
|
||||
@@ -1111,6 +1112,12 @@ declare module 'discord.js' {
|
||||
public push(request: object): void;
|
||||
}
|
||||
|
||||
interface EmbedField {
|
||||
name: string;
|
||||
value: string;
|
||||
inline: boolean;
|
||||
}
|
||||
|
||||
export class RichEmbed {
|
||||
constructor(data?: RichEmbedOptions | MessageEmbed);
|
||||
private _apiTransform(): object;
|
||||
@@ -1129,6 +1136,7 @@ declare module 'discord.js' {
|
||||
public title?: string;
|
||||
public url?: string;
|
||||
public addBlankField(inline?: boolean): this;
|
||||
public spliceFields(index: number, deleteCount: number, ...fields: EmbedFieldData[]): this;
|
||||
public addField(name: StringResolvable, value: StringResolvable, inline?: boolean): this;
|
||||
public attachFile(file: Attachment | FileOptions | string): this;
|
||||
public attachFiles(file: Array<Attachment | FileOptions | string>): this;
|
||||
@@ -1141,6 +1149,7 @@ declare module 'discord.js' {
|
||||
public setTimestamp(timestamp?: Date | number): this;
|
||||
public setTitle(title: StringResolvable): this;
|
||||
public setURL(url: string): this;
|
||||
public static normalizeField(name: StringResolvable, value: StringResolvable, inline?: boolean): EmbedField;
|
||||
}
|
||||
|
||||
export class RichPresenceAssets {
|
||||
@@ -2261,6 +2270,12 @@ declare module 'discord.js' {
|
||||
|
||||
interface RecursiveArray<T> extends Array<T | RecursiveArray<T>> { }
|
||||
|
||||
interface EmbedFieldData {
|
||||
name: StringResolvable;
|
||||
value: StringResolvable;
|
||||
inline?: boolean;
|
||||
}
|
||||
|
||||
type PermissionResolvable = BitFieldResolvable<PermissionString>
|
||||
|
||||
type PremiumTier = number;
|
||||
|
||||
Reference in New Issue
Block a user