refactor(util): make utility functions top level (#8052)

* refactor(util): make functions top level

* types: make channel typeguards more strict

* chore: make requested changes
This commit is contained in:
Suneet Tipirneni
2022-06-13 14:04:53 -04:00
committed by GitHub
parent 51eadf3737
commit e53d162198
39 changed files with 808 additions and 788 deletions

View File

@@ -4,7 +4,7 @@ const EventEmitter = require('node:events');
const { REST } = require('@discordjs/rest'); const { REST } = require('@discordjs/rest');
const { TypeError } = require('../errors'); const { TypeError } = require('../errors');
const Options = require('../util/Options'); const Options = require('../util/Options');
const Util = require('../util/Util'); const { mergeDefault, flatten } = require('../util/Util');
/** /**
* The base class for all clients. * The base class for all clients.
@@ -22,7 +22,7 @@ class BaseClient extends EventEmitter {
* The options the client was instantiated with * The options the client was instantiated with
* @type {ClientOptions} * @type {ClientOptions}
*/ */
this.options = Util.mergeDefault(Options.createDefault(), options); this.options = mergeDefault(Options.createDefault(), options);
/** /**
* The REST manager of the client * The REST manager of the client
@@ -63,7 +63,7 @@ class BaseClient extends EventEmitter {
} }
toJSON(...props) { toJSON(...props) {
return Util.flatten(this, { domain: false }, ...props); return flatten(this, { domain: false }, ...props);
} }
} }

View File

@@ -1,7 +1,7 @@
'use strict'; 'use strict';
const Action = require('./Action'); const Action = require('./Action');
const { Channel } = require('../../structures/Channel'); const { createChannel } = require('../../util/Channels');
class ChannelUpdateAction extends Action { class ChannelUpdateAction extends Action {
handle(data) { handle(data) {
@@ -12,7 +12,7 @@ class ChannelUpdateAction extends Action {
const old = channel._update(data); const old = channel._update(data);
if (channel.type !== data.type) { if (channel.type !== data.type) {
const newChannel = Channel.create(this.client, data, channel.guild); const newChannel = createChannel(this.client, data, channel.guild);
for (const [id, message] of channel.messages.cache) newChannel.messages.cache.set(id, message); for (const [id, message] of channel.messages.cache) newChannel.messages.cache.set(id, message);
channel = newChannel; channel = newChannel;
this.client.channels.cache.set(channel.id, channel); this.client.channels.cache.set(channel.id, channel);

View File

@@ -34,7 +34,7 @@ exports.Sweepers = require('./util/Sweepers');
exports.SystemChannelFlagsBitField = require('./util/SystemChannelFlagsBitField'); exports.SystemChannelFlagsBitField = require('./util/SystemChannelFlagsBitField');
exports.ThreadMemberFlagsBitField = require('./util/ThreadMemberFlagsBitField'); exports.ThreadMemberFlagsBitField = require('./util/ThreadMemberFlagsBitField');
exports.UserFlagsBitField = require('./util/UserFlagsBitField'); exports.UserFlagsBitField = require('./util/UserFlagsBitField');
exports.Util = require('./util/Util'); __exportStar(require('./util/Util.js'), exports);
exports.version = require('../package.json').version; exports.version = require('../package.json').version;
// Managers // Managers

View File

@@ -4,6 +4,7 @@ const process = require('node:process');
const { Routes } = require('discord-api-types/v10'); const { Routes } = require('discord-api-types/v10');
const CachedManager = require('./CachedManager'); const CachedManager = require('./CachedManager');
const { Channel } = require('../structures/Channel'); const { Channel } = require('../structures/Channel');
const { createChannel } = require('../util/Channels');
const { ThreadChannelTypes } = require('../util/Constants'); const { ThreadChannelTypes } = require('../util/Constants');
const Events = require('../util/Events'); const Events = require('../util/Events');
@@ -46,7 +47,7 @@ class ChannelManager extends CachedManager {
return existing; return existing;
} }
const channel = Channel.create(this.client, data, guild, { allowUnknownGuild, fromInteraction }); const channel = createChannel(this.client, data, guild, { allowUnknownGuild, fromInteraction });
if (!channel) { if (!channel) {
this.client.emit(Events.Debug, `Failed to find guild, or unknown type for channel ${data.id} ${data.type}`); this.client.emit(Events.Debug, `Failed to find guild, or unknown type for channel ${data.id} ${data.type}`);

View File

@@ -12,7 +12,7 @@ const ThreadChannel = require('../structures/ThreadChannel');
const Webhook = require('../structures/Webhook'); const Webhook = require('../structures/Webhook');
const { ThreadChannelTypes } = require('../util/Constants'); const { ThreadChannelTypes } = require('../util/Constants');
const DataResolver = require('../util/DataResolver'); const DataResolver = require('../util/DataResolver');
const Util = require('../util/Util'); const { setPosition } = require('../util/Util');
let cacheWarningEmitted = false; let cacheWarningEmitted = false;
@@ -296,7 +296,7 @@ class GuildChannelManager extends CachedManager {
async setPosition(channel, position, { relative, reason } = {}) { async setPosition(channel, position, { relative, reason } = {}) {
channel = this.resolve(channel); channel = this.resolve(channel);
if (!channel) throw new TypeError('INVALID_TYPE', 'channel', 'GuildChannelResolvable'); if (!channel) throw new TypeError('INVALID_TYPE', 'channel', 'GuildChannelResolvable');
const updatedChannels = await Util.setPosition( const updatedChannels = await setPosition(
channel, channel,
position, position,
relative, relative,

View File

@@ -7,7 +7,7 @@ const CachedManager = require('./CachedManager');
const { TypeError } = require('../errors'); const { TypeError } = require('../errors');
const { Message } = require('../structures/Message'); const { Message } = require('../structures/Message');
const MessagePayload = require('../structures/MessagePayload'); const MessagePayload = require('../structures/MessagePayload');
const Util = require('../util/Util'); const { resolvePartialEmoji } = require('../util/Util');
/** /**
* Manages API methods for Messages and holds their cache. * Manages API methods for Messages and holds their cache.
@@ -223,7 +223,7 @@ class MessageManager extends CachedManager {
message = this.resolveId(message); message = this.resolveId(message);
if (!message) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable'); if (!message) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');
emoji = Util.resolvePartialEmoji(emoji); emoji = resolvePartialEmoji(emoji);
if (!emoji) throw new TypeError('EMOJI_TYPE', 'emoji', 'EmojiIdentifierResolvable'); if (!emoji) throw new TypeError('EMOJI_TYPE', 'emoji', 'EmojiIdentifierResolvable');
const emojiId = emoji.id const emojiId = emoji.id

View File

@@ -8,8 +8,7 @@ const { TypeError } = require('../errors');
const { Role } = require('../structures/Role'); const { Role } = require('../structures/Role');
const DataResolver = require('../util/DataResolver'); const DataResolver = require('../util/DataResolver');
const PermissionsBitField = require('../util/PermissionsBitField'); const PermissionsBitField = require('../util/PermissionsBitField');
const { resolveColor } = require('../util/Util'); const { setPosition, resolveColor } = require('../util/Util');
const Util = require('../util/Util');
let cacheWarningEmitted = false; let cacheWarningEmitted = false;
@@ -246,7 +245,7 @@ class RoleManager extends CachedManager {
async setPosition(role, position, { relative, reason } = {}) { async setPosition(role, position, { relative, reason } = {}) {
role = this.resolve(role); role = this.resolve(role);
if (!role) throw new TypeError('INVALID_TYPE', 'role', 'RoleResolvable'); if (!role) throw new TypeError('INVALID_TYPE', 'role', 'RoleResolvable');
const updatedRoles = await Util.setPosition( const updatedRoles = await setPosition(
role, role,
position, position,
relative, relative,

View File

@@ -6,7 +6,7 @@ const process = require('node:process');
const { setTimeout, clearTimeout } = require('node:timers'); const { setTimeout, clearTimeout } = require('node:timers');
const { setTimeout: sleep } = require('node:timers/promises'); const { setTimeout: sleep } = require('node:timers/promises');
const { Error } = require('../errors'); const { Error } = require('../errors');
const Util = require('../util/Util'); const { makeError, makePlainError } = require('../util/Util');
let childProcess = null; let childProcess = null;
let Worker = null; let Worker = null;
@@ -252,7 +252,7 @@ class Shard extends EventEmitter {
this.decrementMaxListeners(child); this.decrementMaxListeners(child);
this._fetches.delete(prop); this._fetches.delete(prop);
if (!message._error) resolve(message._result); if (!message._error) resolve(message._result);
else reject(Util.makeError(message._error)); else reject(makeError(message._error));
}; };
this.incrementMaxListeners(child); this.incrementMaxListeners(child);
@@ -295,7 +295,7 @@ class Shard extends EventEmitter {
this.decrementMaxListeners(child); this.decrementMaxListeners(child);
this._evals.delete(_eval); this._evals.delete(_eval);
if (!message._error) resolve(message._result); if (!message._error) resolve(message._result);
else reject(Util.makeError(message._error)); else reject(makeError(message._error));
}; };
this.incrementMaxListeners(child); this.incrementMaxListeners(child);
@@ -358,7 +358,7 @@ class Shard extends EventEmitter {
const resp = { _sFetchProp: message._sFetchProp, _sFetchPropShard: message._sFetchPropShard }; const resp = { _sFetchProp: message._sFetchProp, _sFetchPropShard: message._sFetchPropShard };
this.manager.fetchClientValues(message._sFetchProp, message._sFetchPropShard).then( this.manager.fetchClientValues(message._sFetchProp, message._sFetchPropShard).then(
results => this.send({ ...resp, _result: results }), results => this.send({ ...resp, _result: results }),
err => this.send({ ...resp, _error: Util.makePlainError(err) }), err => this.send({ ...resp, _error: makePlainError(err) }),
); );
return; return;
} }
@@ -368,7 +368,7 @@ class Shard extends EventEmitter {
const resp = { _sEval: message._sEval, _sEvalShard: message._sEvalShard }; const resp = { _sEval: message._sEval, _sEvalShard: message._sEvalShard };
this.manager._performOnShards('eval', [message._sEval], message._sEvalShard).then( this.manager._performOnShards('eval', [message._sEval], message._sEvalShard).then(
results => this.send({ ...resp, _result: results }), results => this.send({ ...resp, _result: results }),
err => this.send({ ...resp, _error: Util.makePlainError(err) }), err => this.send({ ...resp, _error: makePlainError(err) }),
); );
return; return;
} }

View File

@@ -3,7 +3,7 @@
const process = require('node:process'); const process = require('node:process');
const { Error } = require('../errors'); const { Error } = require('../errors');
const Events = require('../util/Events'); const Events = require('../util/Events');
const Util = require('../util/Util'); const { makeError, makePlainError } = require('../util/Util');
/** /**
* Helper class for sharded clients spawned as a child process/worker, such as from a {@link ShardingManager}. * Helper class for sharded clients spawned as a child process/worker, such as from a {@link ShardingManager}.
@@ -113,7 +113,7 @@ class ShardClientUtil {
parent.removeListener('message', listener); parent.removeListener('message', listener);
this.decrementMaxListeners(parent); this.decrementMaxListeners(parent);
if (!message._error) resolve(message._result); if (!message._error) resolve(message._result);
else reject(Util.makeError(message._error)); else reject(makeError(message._error));
}; };
this.incrementMaxListeners(parent); this.incrementMaxListeners(parent);
parent.on('message', listener); parent.on('message', listener);
@@ -151,7 +151,7 @@ class ShardClientUtil {
parent.removeListener('message', listener); parent.removeListener('message', listener);
this.decrementMaxListeners(parent); this.decrementMaxListeners(parent);
if (!message._error) resolve(message._result); if (!message._error) resolve(message._result);
else reject(Util.makeError(message._error)); else reject(makeError(message._error));
}; };
this.incrementMaxListeners(parent); this.incrementMaxListeners(parent);
parent.on('message', listener); parent.on('message', listener);
@@ -187,13 +187,13 @@ class ShardClientUtil {
for (const prop of props) value = value[prop]; for (const prop of props) value = value[prop];
this._respond('fetchProp', { _fetchProp: message._fetchProp, _result: value }); this._respond('fetchProp', { _fetchProp: message._fetchProp, _result: value });
} catch (err) { } catch (err) {
this._respond('fetchProp', { _fetchProp: message._fetchProp, _error: Util.makePlainError(err) }); this._respond('fetchProp', { _fetchProp: message._fetchProp, _error: makePlainError(err) });
} }
} else if (message._eval) { } else if (message._eval) {
try { try {
this._respond('eval', { _eval: message._eval, _result: await this.client._eval(message._eval) }); this._respond('eval', { _eval: message._eval, _result: await this.client._eval(message._eval) });
} catch (err) { } catch (err) {
this._respond('eval', { _eval: message._eval, _error: Util.makePlainError(err) }); this._respond('eval', { _eval: message._eval, _error: makePlainError(err) });
} }
} }
} }

View File

@@ -8,7 +8,7 @@ const { setTimeout: sleep } = require('node:timers/promises');
const { Collection } = require('@discordjs/collection'); const { Collection } = require('@discordjs/collection');
const Shard = require('./Shard'); const Shard = require('./Shard');
const { Error, TypeError, RangeError } = require('../errors'); const { Error, TypeError, RangeError } = require('../errors');
const Util = require('../util/Util'); const { mergeDefault, fetchRecommendedShards } = require('../util/Util');
/** /**
* This is a utility class that makes multi-process sharding of a bot an easy and painless experience. * This is a utility class that makes multi-process sharding of a bot an easy and painless experience.
@@ -47,7 +47,7 @@ class ShardingManager extends EventEmitter {
*/ */
constructor(file, options = {}) { constructor(file, options = {}) {
super(); super();
options = Util.mergeDefault( options = mergeDefault(
{ {
totalShards: 'auto', totalShards: 'auto',
mode: 'process', mode: 'process',
@@ -183,7 +183,7 @@ class ShardingManager extends EventEmitter {
async spawn({ amount = this.totalShards, delay = 5500, timeout = 30_000 } = {}) { async spawn({ amount = this.totalShards, delay = 5500, timeout = 30_000 } = {}) {
// Obtain/verify the number of shards to spawn // Obtain/verify the number of shards to spawn
if (amount === 'auto') { if (amount === 'auto') {
amount = await Util.fetchRecommendedShards(this.token); amount = await fetchRecommendedShards(this.token);
} else { } else {
if (typeof amount !== 'number' || isNaN(amount)) { if (typeof amount !== 'number' || isNaN(amount)) {
throw new TypeError('CLIENT_INVALID_OPTION', 'Amount of shards', 'a number.'); throw new TypeError('CLIENT_INVALID_OPTION', 'Amount of shards', 'a number.');

View File

@@ -2,7 +2,7 @@
const { isJSONEncodable } = require('@discordjs/builders'); const { isJSONEncodable } = require('@discordjs/builders');
const Component = require('./Component'); const Component = require('./Component');
const Components = require('../util/Components'); const { createComponent } = require('../util/Components');
/** /**
* Represents an action row * Represents an action row
@@ -17,7 +17,7 @@ class ActionRow extends Component {
* @type {Component[]} * @type {Component[]}
* @readonly * @readonly
*/ */
this.components = components.map(c => Components.createComponent(c)); this.components = components.map(c => createComponent(c));
} }
/** /**

View File

@@ -1,8 +1,8 @@
'use strict'; 'use strict';
const { ActionRowBuilder: BuildersActionRow, ComponentBuilder, isJSONEncodable } = require('@discordjs/builders'); const { ActionRowBuilder: BuildersActionRow, ComponentBuilder, isJSONEncodable } = require('@discordjs/builders');
const Components = require('../util/Components'); const { createComponentBuilder } = require('../util/Components');
const Transformers = require('../util/Transformers'); const { toSnakeCase } = require('../util/Transformers');
/** /**
* Represents an action row builder. * Represents an action row builder.
@@ -11,8 +11,8 @@ const Transformers = require('../util/Transformers');
class ActionRowBuilder extends BuildersActionRow { class ActionRowBuilder extends BuildersActionRow {
constructor({ components, ...data } = {}) { constructor({ components, ...data } = {}) {
super({ super({
...Transformers.toSnakeCase(data), ...toSnakeCase(data),
components: components?.map(c => (c instanceof ComponentBuilder ? c : Components.createComponentBuilder(c))), components: components?.map(c => (c instanceof ComponentBuilder ? c : createComponentBuilder(c))),
}); });
} }

View File

@@ -1,6 +1,6 @@
'use strict'; 'use strict';
const Util = require('../util/Util'); const { basename, flatten } = require('../util/Util');
/** /**
* @typedef {Object} AttachmentPayload * @typedef {Object} AttachmentPayload
@@ -107,11 +107,11 @@ class Attachment {
* @readonly * @readonly
*/ */
get spoiler() { get spoiler() {
return Util.basename(this.url ?? this.name).startsWith('SPOILER_'); return basename(this.url ?? this.name).startsWith('SPOILER_');
} }
toJSON() { toJSON() {
return Util.flatten(this); return flatten(this);
} }
} }

View File

@@ -1,6 +1,6 @@
'use strict'; 'use strict';
const Util = require('../util/Util'); const { basename, flatten } = require('../util/Util');
/** /**
* Represents an attachment builder * Represents an attachment builder
@@ -82,11 +82,11 @@ class AttachmentBuilder {
* @readonly * @readonly
*/ */
get spoiler() { get spoiler() {
return Util.basename(this.name).startsWith('SPOILER_'); return basename(this.name).startsWith('SPOILER_');
} }
toJSON() { toJSON() {
return Util.flatten(this); return flatten(this);
} }
/** /**

View File

@@ -1,6 +1,6 @@
'use strict'; 'use strict';
const Util = require('../util/Util'); const { flatten } = require('../util/Util');
/** /**
* Represents a data model that is identifiable by a Snowflake (i.e. Discord API data models). * Represents a data model that is identifiable by a Snowflake (i.e. Discord API data models).
@@ -32,7 +32,7 @@ class Base {
} }
toJSON(...props) { toJSON(...props) {
return Util.flatten(this, ...props); return flatten(this, ...props);
} }
valueOf() { valueOf() {

View File

@@ -1,8 +1,8 @@
'use strict'; 'use strict';
const { ButtonBuilder: BuildersButton, isJSONEncodable } = require('@discordjs/builders'); const { ButtonBuilder: BuildersButton, isJSONEncodable } = require('@discordjs/builders');
const Transformers = require('../util/Transformers'); const { toSnakeCase } = require('../util/Transformers');
const Util = require('../util/Util'); const { parseEmoji } = require('../util/Util');
/** /**
* Represents a button builder. * Represents a button builder.
@@ -10,9 +10,7 @@ const Util = require('../util/Util');
*/ */
class ButtonBuilder extends BuildersButton { class ButtonBuilder extends BuildersButton {
constructor({ emoji, ...data } = {}) { constructor({ emoji, ...data } = {}) {
super( super(toSnakeCase({ ...data, emoji: emoji && typeof emoji === 'string' ? parseEmoji(emoji) : emoji }));
Transformers.toSnakeCase({ ...data, emoji: emoji && typeof emoji === 'string' ? Util.parseEmoji(emoji) : emoji }),
);
} }
/** /**
@@ -22,7 +20,7 @@ class ButtonBuilder extends BuildersButton {
*/ */
setEmoji(emoji) { setEmoji(emoji) {
if (typeof emoji === 'string') { if (typeof emoji === 'string') {
return super.setEmoji(Util.parseEmoji(emoji)); return super.setEmoji(parseEmoji(emoji));
} }
return super.setEmoji(emoji); return super.setEmoji(emoji);
} }

View File

@@ -4,14 +4,6 @@ const { DiscordSnowflake } = require('@sapphire/snowflake');
const { ChannelType, Routes } = require('discord-api-types/v10'); const { ChannelType, Routes } = require('discord-api-types/v10');
const Base = require('./Base'); const Base = require('./Base');
const { ThreadChannelTypes } = require('../util/Constants'); const { ThreadChannelTypes } = require('../util/Constants');
let CategoryChannel;
let DMChannel;
let NewsChannel;
let StageChannel;
let TextChannel;
let ThreadChannel;
let VoiceChannel;
let DirectoryChannel;
/** /**
* Represents any channel on Discord. * Represents any channel on Discord.
@@ -142,66 +134,6 @@ class Channel extends Base {
return 'bitrate' in this; return 'bitrate' in this;
} }
static create(client, data, guild, { allowUnknownGuild, fromInteraction } = {}) {
CategoryChannel ??= require('./CategoryChannel');
DMChannel ??= require('./DMChannel');
NewsChannel ??= require('./NewsChannel');
StageChannel ??= require('./StageChannel');
TextChannel ??= require('./TextChannel');
ThreadChannel ??= require('./ThreadChannel');
VoiceChannel ??= require('./VoiceChannel');
DirectoryChannel ??= require('./DirectoryChannel');
let channel;
if (!data.guild_id && !guild) {
if ((data.recipients && data.type !== ChannelType.GroupDM) || data.type === ChannelType.DM) {
channel = new DMChannel(client, data);
} else if (data.type === ChannelType.GroupDM) {
const PartialGroupDMChannel = require('./PartialGroupDMChannel');
channel = new PartialGroupDMChannel(client, data);
}
} else {
guild ??= client.guilds.cache.get(data.guild_id);
if (guild || allowUnknownGuild) {
switch (data.type) {
case ChannelType.GuildText: {
channel = new TextChannel(guild, data, client);
break;
}
case ChannelType.GuildVoice: {
channel = new VoiceChannel(guild, data, client);
break;
}
case ChannelType.GuildCategory: {
channel = new CategoryChannel(guild, data, client);
break;
}
case ChannelType.GuildNews: {
channel = new NewsChannel(guild, data, client);
break;
}
case ChannelType.GuildStageVoice: {
channel = new StageChannel(guild, data, client);
break;
}
case ChannelType.GuildNewsThread:
case ChannelType.GuildPublicThread:
case ChannelType.GuildPrivateThread: {
channel = new ThreadChannel(guild, data, client, fromInteraction);
if (!allowUnknownGuild) channel.parent?.threads.cache.set(channel.id, channel);
break;
}
case ChannelType.GuildDirectory:
channel = new DirectoryChannel(guild, data, client);
break;
}
if (channel && !allowUnknownGuild) guild.channels?.cache.set(channel.id, channel);
}
}
return channel;
}
toJSON(...props) { toJSON(...props) {
return super.toJSON({ createdTimestamp: true }, ...props); return super.toJSON({ createdTimestamp: true }, ...props);
} }

View File

@@ -1,8 +1,8 @@
'use strict'; 'use strict';
const { EmbedBuilder: BuildersEmbed, isJSONEncodable } = require('@discordjs/builders'); const { EmbedBuilder: BuildersEmbed, isJSONEncodable } = require('@discordjs/builders');
const Transformers = require('../util/Transformers'); const { toSnakeCase } = require('../util/Transformers');
const Util = require('../util/Util'); const { resolveColor } = require('../util/Util');
/** /**
* Represents an embed builder. * Represents an embed builder.
@@ -10,7 +10,7 @@ const Util = require('../util/Util');
*/ */
class EmbedBuilder extends BuildersEmbed { class EmbedBuilder extends BuildersEmbed {
constructor(data) { constructor(data) {
super(Transformers.toSnakeCase(data)); super(toSnakeCase(data));
} }
/** /**
@@ -19,7 +19,7 @@ class EmbedBuilder extends BuildersEmbed {
* @returns {EmbedBuilder} * @returns {EmbedBuilder}
*/ */
setColor(color) { setColor(color) {
return super.setColor(color && Util.resolveColor(color)); return super.setColor(color && resolveColor(color));
} }
/** /**

View File

@@ -27,7 +27,7 @@ const VoiceStateManager = require('../managers/VoiceStateManager');
const DataResolver = require('../util/DataResolver'); const DataResolver = require('../util/DataResolver');
const Status = require('../util/Status'); const Status = require('../util/Status');
const SystemChannelFlagsBitField = require('../util/SystemChannelFlagsBitField'); const SystemChannelFlagsBitField = require('../util/SystemChannelFlagsBitField');
const Util = require('../util/Util'); const { discordSort } = require('../util/Util');
/** /**
* Represents a guild (or a server) on Discord. * Represents a guild (or a server) on Discord.
@@ -1253,7 +1253,7 @@ class Guild extends AnonymousGuild {
* @private * @private
*/ */
_sortedRoles() { _sortedRoles() {
return Util.discordSort(this.roles.cache); return discordSort(this.roles.cache);
} }
/** /**
@@ -1265,7 +1265,7 @@ class Guild extends AnonymousGuild {
_sortedChannels(channel) { _sortedChannels(channel) {
const category = channel.type === ChannelType.GuildCategory; const category = channel.type === ChannelType.GuildCategory;
const channelTypes = [ChannelType.GuildText, ChannelType.GuildNews]; const channelTypes = [ChannelType.GuildText, ChannelType.GuildNews];
return Util.discordSort( return discordSort(
this.channels.cache.filter( this.channels.cache.filter(
c => c =>
(channelTypes.includes(channel.type) ? channelTypes.includes(c.type) : c.type === channel.type) && (channelTypes.includes(channel.type) ? channelTypes.includes(c.type) : c.type === channel.type) &&

View File

@@ -5,7 +5,7 @@ const ApplicationCommand = require('./ApplicationCommand');
const GuildAuditLogsEntry = require('./GuildAuditLogsEntry'); const GuildAuditLogsEntry = require('./GuildAuditLogsEntry');
const Integration = require('./Integration'); const Integration = require('./Integration');
const Webhook = require('./Webhook'); const Webhook = require('./Webhook');
const Util = require('../util/Util'); const { flatten } = require('../util/Util');
/** /**
* The target type of an entry. Here are the available types: * The target type of an entry. Here are the available types:
@@ -92,7 +92,7 @@ class GuildAuditLogs {
} }
toJSON() { toJSON() {
return Util.flatten(this); return flatten(this);
} }
} }

View File

@@ -9,7 +9,7 @@ const { StageInstance } = require('./StageInstance');
const { Sticker } = require('./Sticker'); const { Sticker } = require('./Sticker');
const Webhook = require('./Webhook'); const Webhook = require('./Webhook');
const Partials = require('../util/Partials'); const Partials = require('../util/Partials');
const Util = require('../util/Util'); const { flatten } = require('../util/Util');
const Targets = { const Targets = {
All: 'All', All: 'All',
@@ -459,7 +459,7 @@ class GuildAuditLogsEntry {
} }
toJSON() { toJSON() {
return Util.flatten(this, { createdTimestamp: true }); return flatten(this, { createdTimestamp: true });
} }
} }

View File

@@ -20,11 +20,11 @@ const ReactionCollector = require('./ReactionCollector');
const { Sticker } = require('./Sticker'); const { Sticker } = require('./Sticker');
const { Error } = require('../errors'); const { Error } = require('../errors');
const ReactionManager = require('../managers/ReactionManager'); const ReactionManager = require('../managers/ReactionManager');
const Components = require('../util/Components'); const { createComponent } = require('../util/Components');
const { NonSystemMessageTypes } = require('../util/Constants'); const { NonSystemMessageTypes } = require('../util/Constants');
const MessageFlagsBitField = require('../util/MessageFlagsBitField'); const MessageFlagsBitField = require('../util/MessageFlagsBitField');
const PermissionsBitField = require('../util/PermissionsBitField'); const PermissionsBitField = require('../util/PermissionsBitField');
const Util = require('../util/Util'); const { cleanContent, resolvePartialEmoji } = require('../util/Util');
/** /**
* Represents a message on Discord. * Represents a message on Discord.
@@ -146,7 +146,7 @@ class Message extends Base {
* A list of MessageActionRows in the message * A list of MessageActionRows in the message
* @type {ActionRow[]} * @type {ActionRow[]}
*/ */
this.components = data.components.map(c => Components.createComponent(c)); this.components = data.components.map(c => createComponent(c));
} else { } else {
this.components = this.components?.slice() ?? []; this.components = this.components?.slice() ?? [];
} }
@@ -441,7 +441,7 @@ class Message extends Base {
*/ */
get cleanContent() { get cleanContent() {
// eslint-disable-next-line eqeqeq // eslint-disable-next-line eqeqeq
return this.content != null ? Util.cleanContent(this.content, this.channel) : null; return this.content != null ? cleanContent(this.content, this.channel) : null;
} }
/** /**
@@ -737,7 +737,7 @@ class Message extends Base {
user: this.client.user, user: this.client.user,
channel: this.channel, channel: this.channel,
message: this, message: this,
emoji: Util.resolvePartialEmoji(emoji), emoji: resolvePartialEmoji(emoji),
}, },
true, true,
).reaction; ).reaction;

View File

@@ -1,7 +1,7 @@
'use strict'; 'use strict';
const { Collection } = require('@discordjs/collection'); const { Collection } = require('@discordjs/collection');
const Util = require('../util/Util'); const { flatten } = require('../util/Util');
/** /**
* Keeps track of mentions in a {@link Message}. * Keeps track of mentions in a {@link Message}.
@@ -233,7 +233,7 @@ class MessageMentions {
} }
toJSON() { toJSON() {
return Util.flatten(this, { return flatten(this, {
members: true, members: true,
channels: true, channels: true,
}); });

View File

@@ -7,7 +7,7 @@ const ActionRowBuilder = require('./ActionRowBuilder');
const { RangeError } = require('../errors'); const { RangeError } = require('../errors');
const DataResolver = require('../util/DataResolver'); const DataResolver = require('../util/DataResolver');
const MessageFlagsBitField = require('../util/MessageFlagsBitField'); const MessageFlagsBitField = require('../util/MessageFlagsBitField');
const Util = require('../util/Util'); const { basename, cloneObject, verifyString } = require('../util/Util');
/** /**
* Represents a message to be sent to the API. * Represents a message to be sent to the API.
@@ -105,7 +105,7 @@ class MessagePayload {
if (this.options.content === null) { if (this.options.content === null) {
content = ''; content = '';
} else if (typeof this.options.content !== 'undefined') { } else if (typeof this.options.content !== 'undefined') {
content = Util.verifyString(this.options.content, RangeError, 'MESSAGE_CONTENT_TYPE', true); content = verifyString(this.options.content, RangeError, 'MESSAGE_CONTENT_TYPE', true);
} }
return content; return content;
@@ -164,7 +164,7 @@ class MessagePayload {
: this.options.allowedMentions; : this.options.allowedMentions;
if (allowedMentions) { if (allowedMentions) {
allowedMentions = Util.cloneObject(allowedMentions); allowedMentions = cloneObject(allowedMentions);
allowedMentions.replied_user = allowedMentions.repliedUser; allowedMentions.replied_user = allowedMentions.repliedUser;
delete allowedMentions.repliedUser; delete allowedMentions.repliedUser;
} }
@@ -234,11 +234,11 @@ class MessagePayload {
const findName = thing => { const findName = thing => {
if (typeof thing === 'string') { if (typeof thing === 'string') {
return Util.basename(thing); return basename(thing);
} }
if (thing.path) { if (thing.path) {
return Util.basename(thing.path); return basename(thing.path);
} }
return 'file.jpg'; return 'file.jpg';

View File

@@ -4,7 +4,7 @@ const { Routes } = require('discord-api-types/v10');
const GuildEmoji = require('./GuildEmoji'); const GuildEmoji = require('./GuildEmoji');
const ReactionEmoji = require('./ReactionEmoji'); const ReactionEmoji = require('./ReactionEmoji');
const ReactionUserManager = require('../managers/ReactionUserManager'); const ReactionUserManager = require('../managers/ReactionUserManager');
const Util = require('../util/Util'); const { flatten } = require('../util/Util');
/** /**
* Represents a reaction to a message. * Represents a reaction to a message.
@@ -114,7 +114,7 @@ class MessageReaction {
} }
toJSON() { toJSON() {
return Util.flatten(this, { emoji: 'emojiId', message: 'messageId' }); return flatten(this, { emoji: 'emojiId', message: 'messageId' });
} }
_add(user) { _add(user) {

View File

@@ -1,7 +1,7 @@
'use strict'; 'use strict';
const { ModalBuilder: BuildersModal, ComponentBuilder, isJSONEncodable } = require('@discordjs/builders'); const { ModalBuilder: BuildersModal, ComponentBuilder, isJSONEncodable } = require('@discordjs/builders');
const Transformers = require('../util/Transformers'); const { toSnakeCase } = require('../util/Transformers');
/** /**
* Represents a modal builder. * Represents a modal builder.
@@ -10,8 +10,8 @@ const Transformers = require('../util/Transformers');
class ModalBuilder extends BuildersModal { class ModalBuilder extends BuildersModal {
constructor({ components, ...data } = {}) { constructor({ components, ...data } = {}) {
super({ super({
...Transformers.toSnakeCase(data), ...toSnakeCase(data),
components: components?.map(c => (c instanceof ComponentBuilder ? c : Transformers.toSnakeCase(c))), components: components?.map(c => (c instanceof ComponentBuilder ? c : toSnakeCase(c))),
}); });
} }

View File

@@ -3,7 +3,7 @@
const Base = require('./Base'); const Base = require('./Base');
const { Emoji } = require('./Emoji'); const { Emoji } = require('./Emoji');
const ActivityFlagsBitField = require('../util/ActivityFlagsBitField'); const ActivityFlagsBitField = require('../util/ActivityFlagsBitField');
const Util = require('../util/Util'); const { flatten } = require('../util/Util');
/** /**
* Activity sent in a message. * Activity sent in a message.
@@ -132,7 +132,7 @@ class Presence extends Base {
} }
toJSON() { toJSON() {
return Util.flatten(this); return flatten(this);
} }
} }

View File

@@ -1,7 +1,7 @@
'use strict'; 'use strict';
const { Emoji } = require('./Emoji'); const { Emoji } = require('./Emoji');
const Util = require('../util/Util'); const { flatten } = require('../util/Util');
/** /**
* Represents a limited emoji set used for both custom and unicode emojis. Custom emojis * Represents a limited emoji set used for both custom and unicode emojis. Custom emojis
@@ -20,7 +20,7 @@ class ReactionEmoji extends Emoji {
} }
toJSON() { toJSON() {
return Util.flatten(this, { identifier: true }); return flatten(this, { identifier: true });
} }
valueOf() { valueOf() {

View File

@@ -1,8 +1,8 @@
'use strict'; 'use strict';
const { SelectMenuBuilder: BuildersSelectMenu, isJSONEncodable, normalizeArray } = require('@discordjs/builders'); const { SelectMenuBuilder: BuildersSelectMenu, isJSONEncodable, normalizeArray } = require('@discordjs/builders');
const Transformers = require('../util/Transformers'); const { toSnakeCase } = require('../util/Transformers');
const Util = require('../util/Util'); const { parseEmoji } = require('../util/Util');
/** /**
* Class used to build select menu components to be sent through the API * Class used to build select menu components to be sent through the API
@@ -11,11 +11,11 @@ const Util = require('../util/Util');
class SelectMenuBuilder extends BuildersSelectMenu { class SelectMenuBuilder extends BuildersSelectMenu {
constructor({ options, ...data } = {}) { constructor({ options, ...data } = {}) {
super( super(
Transformers.toSnakeCase({ toSnakeCase({
...data, ...data,
options: options?.map(({ emoji, ...option }) => ({ options: options?.map(({ emoji, ...option }) => ({
...option, ...option,
emoji: emoji && typeof emoji === 'string' ? Util.parseEmoji(emoji) : emoji, emoji: emoji && typeof emoji === 'string' ? parseEmoji(emoji) : emoji,
})), })),
}), }),
); );
@@ -30,7 +30,7 @@ class SelectMenuBuilder extends BuildersSelectMenu {
return super.addOptions( return super.addOptions(
normalizeArray(options).map(({ emoji, ...option }) => ({ normalizeArray(options).map(({ emoji, ...option }) => ({
...option, ...option,
emoji: emoji && typeof emoji === 'string' ? Util.parseEmoji(emoji) : emoji, emoji: emoji && typeof emoji === 'string' ? parseEmoji(emoji) : emoji,
})), })),
); );
} }
@@ -44,7 +44,7 @@ class SelectMenuBuilder extends BuildersSelectMenu {
return super.setOptions( return super.setOptions(
normalizeArray(options).map(({ emoji, ...option }) => ({ normalizeArray(options).map(({ emoji, ...option }) => ({
...option, ...option,
emoji: emoji && typeof emoji === 'string' ? Util.parseEmoji(emoji) : emoji, emoji: emoji && typeof emoji === 'string' ? parseEmoji(emoji) : emoji,
})), })),
); );
} }

View File

@@ -1,8 +1,8 @@
'use strict'; 'use strict';
const { SelectMenuOptionBuilder: BuildersSelectMenuOption, isJSONEncodable } = require('@discordjs/builders'); const { SelectMenuOptionBuilder: BuildersSelectMenuOption, isJSONEncodable } = require('@discordjs/builders');
const Transformers = require('../util/Transformers'); const { toSnakeCase } = require('../util/Transformers');
const Util = require('../util/Util'); const { parseEmoji } = require('../util/Util');
/** /**
* Represents a select menu option builder. * Represents a select menu option builder.
@@ -11,9 +11,9 @@ const Util = require('../util/Util');
class SelectMenuOptionBuilder extends BuildersSelectMenuOption { class SelectMenuOptionBuilder extends BuildersSelectMenuOption {
constructor({ emoji, ...data } = {}) { constructor({ emoji, ...data } = {}) {
super( super(
Transformers.toSnakeCase({ toSnakeCase({
...data, ...data,
emoji: emoji && typeof emoji === 'string' ? Util.parseEmoji(emoji) : emoji, emoji: emoji && typeof emoji === 'string' ? parseEmoji(emoji) : emoji,
}), }),
); );
} }
@@ -24,7 +24,7 @@ class SelectMenuOptionBuilder extends BuildersSelectMenuOption {
*/ */
setEmoji(emoji) { setEmoji(emoji) {
if (typeof emoji === 'string') { if (typeof emoji === 'string') {
return super.setEmoji(Util.parseEmoji(emoji)); return super.setEmoji(parseEmoji(emoji));
} }
return super.setEmoji(emoji); return super.setEmoji(emoji);
} }

View File

@@ -1,7 +1,7 @@
'use strict'; 'use strict';
const { TextInputBuilder: BuildersTextInput, isJSONEncodable } = require('@discordjs/builders'); const { TextInputBuilder: BuildersTextInput, isJSONEncodable } = require('@discordjs/builders');
const Transformers = require('../util/Transformers'); const { toSnakeCase } = require('../util/Transformers');
/** /**
* Represents a text input builder. * Represents a text input builder.
@@ -9,7 +9,7 @@ const Transformers = require('../util/Transformers');
*/ */
class TextInputBuilder extends BuildersTextInput { class TextInputBuilder extends BuildersTextInput {
constructor(data) { constructor(data) {
super(Transformers.toSnakeCase(data)); super(toSnakeCase(data));
} }
/** /**

View File

@@ -1,6 +1,6 @@
'use strict'; 'use strict';
const Util = require('../util/Util'); const { flatten } = require('../util/Util');
/** /**
* Represents a Discord voice region for guilds. * Represents a Discord voice region for guilds.
@@ -39,7 +39,7 @@ class VoiceRegion {
} }
toJSON() { toJSON() {
return Util.flatten(this); return flatten(this);
} }
} }

View File

@@ -4,7 +4,7 @@ const EventEmitter = require('node:events');
const { setTimeout, clearTimeout } = require('node:timers'); const { setTimeout, clearTimeout } = require('node:timers');
const { Collection } = require('@discordjs/collection'); const { Collection } = require('@discordjs/collection');
const { TypeError } = require('../../errors'); const { TypeError } = require('../../errors');
const Util = require('../../util/Util'); const { flatten } = require('../../util/Util');
/** /**
* Filter to be applied to the collector. * Filter to be applied to the collector.
@@ -281,7 +281,7 @@ class Collector extends EventEmitter {
} }
toJSON() { toJSON() {
return Util.flatten(this); return flatten(this);
} }
/* eslint-disable no-empty-function */ /* eslint-disable no-empty-function */

View File

@@ -0,0 +1,72 @@
'use strict';
const { ChannelType } = require('discord-api-types/v10');
const { lazy } = require('./Util');
const getCategoryChannel = lazy(() => require('../structures/CategoryChannel'));
const getDMChannel = lazy(() => require('../structures/DMChannel'));
const getNewsChannel = lazy(() => require('../structures/NewsChannel'));
const getStageChannel = lazy(() => require('../structures/StageChannel'));
const getTextChannel = lazy(() => require('../structures/TextChannel'));
const getThreadChannel = lazy(() => require('../structures/ThreadChannel'));
const getVoiceChannel = lazy(() => require('../structures/VoiceChannel'));
const getDirectoryChannel = lazy(() => require('../structures/DirectoryChannel'));
const getPartialGroupDMChannel = lazy(() => require('../structures/PartialGroupDMChannel'));
// eslint-disable-next-line valid-jsdoc
/**
* @private
*/
function createChannel(client, data, guild, { allowUnknownGuild, fromInteraction } = {}) {
let channel;
if (!data.guild_id && !guild) {
if ((data.recipients && data.type !== ChannelType.GroupDM) || data.type === ChannelType.DM) {
channel = new (getDMChannel())(client, data);
} else if (data.type === ChannelType.GroupDM) {
channel = new (getPartialGroupDMChannel())(client, data);
}
} else {
guild ??= client.guilds.cache.get(data.guild_id);
if (guild || allowUnknownGuild) {
switch (data.type) {
case ChannelType.GuildText: {
channel = new (getTextChannel())(guild, data, client);
break;
}
case ChannelType.GuildVoice: {
channel = new (getVoiceChannel())(guild, data, client);
break;
}
case ChannelType.GuildCategory: {
channel = new (getCategoryChannel())(guild, data, client);
break;
}
case ChannelType.GuildNews: {
channel = new (getNewsChannel())(guild, data, client);
break;
}
case ChannelType.GuildStageVoice: {
channel = new (getStageChannel())(guild, data, client);
break;
}
case ChannelType.GuildNewsThread:
case ChannelType.GuildPublicThread:
case ChannelType.GuildPrivateThread: {
channel = new (getThreadChannel())(guild, data, client, fromInteraction);
if (!allowUnknownGuild) channel.parent?.threads.cache.set(channel.id, channel);
break;
}
case ChannelType.GuildDirectory:
channel = new (getDirectoryChannel())(guild, data, client);
break;
}
if (channel && !allowUnknownGuild) guild.channels?.cache.set(channel.id, channel);
}
}
return channel;
}
module.exports = {
createChannel,
};

View File

@@ -67,57 +67,55 @@ const { ComponentType } = require('discord-api-types/v10');
* @typedef {APIMessageComponentEmoji|string} ComponentEmojiResolvable * @typedef {APIMessageComponentEmoji|string} ComponentEmojiResolvable
*/ */
class Components extends null { /**
/** * Transforms API data into a component
* Transforms API data into a component * @param {APIMessageComponent|Component} data The data to create the component from
* @param {APIMessageComponent|Component} data The data to create the component from * @returns {Component}
* @returns {Component} */
*/ function createComponent(data) {
static createComponent(data) { if (data instanceof Component) {
if (data instanceof Component) { return data;
return data;
}
switch (data.type) {
case ComponentType.ActionRow:
return new ActionRow(data);
case ComponentType.Button:
return new ButtonComponent(data);
case ComponentType.SelectMenu:
return new SelectMenuComponent(data);
case ComponentType.TextInput:
return new TextInputComponent(data);
default:
throw new Error(`Found unknown component type: ${data.type}`);
}
} }
/** switch (data.type) {
* Transforms API data into a component builder case ComponentType.ActionRow:
* @param {APIMessageComponent|ComponentBuilder} data The data to create the component from return new ActionRow(data);
* @returns {ComponentBuilder} case ComponentType.Button:
*/ return new ButtonComponent(data);
static createComponentBuilder(data) { case ComponentType.SelectMenu:
if (data instanceof ComponentBuilder) { return new SelectMenuComponent(data);
return data; case ComponentType.TextInput:
} return new TextInputComponent(data);
default:
switch (data.type) { throw new Error(`Found unknown component type: ${data.type}`);
case ComponentType.ActionRow:
return new ActionRowBuilder(data);
case ComponentType.Button:
return new ButtonBuilder(data);
case ComponentType.SelectMenu:
return new SelectMenuBuilder(data);
case ComponentType.TextInput:
return new TextInputComponent(data);
default:
throw new Error(`Found unknown component type: ${data.type}`);
}
} }
} }
module.exports = Components; /**
* Transforms API data into a component builder
* @param {APIMessageComponent|ComponentBuilder} data The data to create the component from
* @returns {ComponentBuilder}
*/
function createComponentBuilder(data) {
if (data instanceof ComponentBuilder) {
return data;
}
switch (data.type) {
case ComponentType.ActionRow:
return new ActionRowBuilder(data);
case ComponentType.Button:
return new ButtonBuilder(data);
case ComponentType.SelectMenu:
return new SelectMenuBuilder(data);
case ComponentType.TextInput:
return new TextInputComponent(data);
default:
throw new Error(`Found unknown component type: ${data.type}`);
}
}
module.exports = { createComponent, createComponentBuilder };
const ActionRow = require('../structures/ActionRow'); const ActionRow = require('../structures/ActionRow');
const ActionRowBuilder = require('../structures/ActionRowBuilder'); const ActionRowBuilder = require('../structures/ActionRowBuilder');

View File

@@ -2,7 +2,7 @@
const process = require('node:process'); const process = require('node:process');
const { DefaultRestOptions } = require('@discordjs/rest'); const { DefaultRestOptions } = require('@discordjs/rest');
const Transformers = require('./Transformers'); const { toSnakeCase } = require('./Transformers');
/** /**
* @typedef {Function} CacheFactory * @typedef {Function} CacheFactory
@@ -93,7 +93,7 @@ class Options extends null {
version: 10, version: 10,
}, },
rest: DefaultRestOptions, rest: DefaultRestOptions,
jsonTransformer: Transformers.toSnakeCase, jsonTransformer: toSnakeCase,
}; };
} }

View File

@@ -2,19 +2,15 @@
const snakeCase = require('lodash.snakecase'); const snakeCase = require('lodash.snakecase');
class Transformers extends null { /**
/** * Transforms camel-cased keys into snake cased keys
* Transforms camel-cased keys into snake cased keys * @param {*} obj The object to transform
* @param {*} obj The object to transform * @returns {*}
* @returns {*} */
*/ function toSnakeCase(obj) {
static toSnakeCase(obj) { if (typeof obj !== 'object' || !obj) return obj;
if (typeof obj !== 'object' || !obj) return obj; if (Array.isArray(obj)) return obj.map(toSnakeCase);
if (Array.isArray(obj)) return obj.map(Transformers.toSnakeCase); return Object.fromEntries(Object.entries(obj).map(([key, value]) => [snakeCase(key), toSnakeCase(value)]));
return Object.fromEntries(
Object.entries(obj).map(([key, value]) => [snakeCase(key), Transformers.toSnakeCase(value)]),
);
}
} }
module.exports = Transformers; module.exports = { toSnakeCase };

File diff suppressed because it is too large Load Diff

View File

@@ -119,6 +119,7 @@ import {
LocaleString, LocaleString,
MessageActivityType, MessageActivityType,
APIAttachment, APIAttachment,
APIChannel,
} from 'discord-api-types/v10'; } from 'discord-api-types/v10';
import { ChildProcess } from 'node:child_process'; import { ChildProcess } from 'node:child_process';
import { EventEmitter } from 'node:events'; import { EventEmitter } from 'node:events';
@@ -2613,43 +2614,40 @@ export class UserFlagsBitField extends BitField<UserFlagsString> {
public static resolve(bit?: BitFieldResolvable<UserFlagsString, number>): number; public static resolve(bit?: BitFieldResolvable<UserFlagsString, number>): number;
} }
export class Util extends null { export function basename(path: string, ext?: string): string;
private constructor(); export function cleanContent(str: string, channel: TextBasedChannel): string;
public static basename(path: string, ext?: string): string; export function cloneObject(obj: unknown): unknown;
public static cleanContent(str: string, channel: TextBasedChannel): string; export function discordSort<K, V extends { rawPosition: number; id: Snowflake }>(
public static cloneObject(obj: unknown): unknown; collection: Collection<K, V>,
public static discordSort<K, V extends { rawPosition: number; id: Snowflake }>( ): Collection<K, V>;
collection: Collection<K, V>, export function escapeMarkdown(text: string, options?: EscapeMarkdownOptions): string;
): Collection<K, V>; export function escapeCodeBlock(text: string): string;
public static escapeMarkdown(text: string, options?: EscapeMarkdownOptions): string; export function escapeInlineCode(text: string): string;
public static escapeCodeBlock(text: string): string; export function escapeBold(text: string): string;
public static escapeInlineCode(text: string): string; export function escapeItalic(text: string): string;
public static escapeBold(text: string): string; export function escapeUnderline(text: string): string;
public static escapeItalic(text: string): string; export function escapeStrikethrough(text: string): string;
public static escapeUnderline(text: string): string; export function escapeSpoiler(text: string): string;
public static escapeStrikethrough(text: string): string; export function cleanCodeBlockContent(text: string): string;
public static escapeSpoiler(text: string): string; export function fetchRecommendedShards(token: string, options?: FetchRecommendedShardsOptions): Promise<number>;
public static cleanCodeBlockContent(text: string): string; export function flatten(obj: unknown, ...props: Record<string, boolean | string>[]): unknown;
public static fetchRecommendedShards(token: string, options?: FetchRecommendedShardsOptions): Promise<number>; export function makeError(obj: MakeErrorOptions): Error;
public static flatten(obj: unknown, ...props: Record<string, boolean | string>[]): unknown; export function makePlainError(err: Error): MakeErrorOptions;
public static makeError(obj: MakeErrorOptions): Error; export function mergeDefault(def: unknown, given: unknown): unknown;
public static makePlainError(err: Error): MakeErrorOptions; export function moveElementInArray(array: unknown[], element: unknown, newIndex: number, offset?: boolean): number;
public static mergeDefault(def: unknown, given: unknown): unknown; export function parseEmoji(text: string): { animated: boolean; name: string; id: Snowflake | null } | null;
public static moveElementInArray(array: unknown[], element: unknown, newIndex: number, offset?: boolean): number; export function resolveColor(color: ColorResolvable): number;
public static parseEmoji(text: string): { animated: boolean; name: string; id: Snowflake | null } | null; export function resolvePartialEmoji(emoji: EmojiIdentifierResolvable): Partial<APIPartialEmoji> | null;
public static resolveColor(color: ColorResolvable): number; export function verifyString(data: string, error?: typeof Error, errorMessage?: string, allowEmpty?: boolean): string;
public static resolvePartialEmoji(emoji: EmojiIdentifierResolvable): Partial<APIPartialEmoji> | null; export function setPosition<T extends AnyChannel | Role>(
public static verifyString(data: string, error?: typeof Error, errorMessage?: string, allowEmpty?: boolean): string; item: T,
public static setPosition<T extends AnyChannel | Role>( position: number,
item: T, relative: boolean,
position: number, sorted: Collection<Snowflake, T>,
relative: boolean, client: Client,
sorted: Collection<Snowflake, T>, route: string,
client: Client, reason?: string,
route: string, ): Promise<{ id: Snowflake; position: number }[]>;
reason?: string,
): Promise<{ id: Snowflake; position: number }[]>;
}
export interface MappedComponentBuilderTypes { export interface MappedComponentBuilderTypes {
[ComponentType.Button]: ButtonBuilder; [ComponentType.Button]: ButtonBuilder;
@@ -2665,19 +2663,24 @@ export interface MappedComponentTypes {
[ComponentType.TextInput]: TextInputComponent; [ComponentType.TextInput]: TextInputComponent;
} }
export class Components extends null { export interface CreateChannelOptions {
public static createComponent<T extends keyof MappedComponentTypes>( allowFromUnknownGuild?: boolean;
data: APIMessageComponent & { type: T }, fromInteraction?: boolean;
): MappedComponentTypes[T];
public static createComponent<C extends Component>(data: C): C;
public static createComponent(data: APIMessageComponent | Component): Component;
public static createComponentBuilder<T extends keyof MappedComponentBuilderTypes>(
data: APIMessageComponent & { type: T },
): MappedComponentBuilderTypes[T];
public static createComponentBuilder<C extends ComponentBuilder>(data: C): C;
public static createComponentBuilder(data: APIMessageComponent | ComponentBuilder): ComponentBuilder;
} }
export function createChannel(client: Client, data: APIChannel, options?: CreateChannelOptions): AnyChannel;
export function createComponent<T extends keyof MappedComponentTypes>(
data: APIMessageComponent & { type: T },
): MappedComponentTypes[T];
export function createComponent<C extends Component>(data: C): C;
export function createComponent(data: APIMessageComponent | Component): Component;
export function createComponentBuilder<T extends keyof MappedComponentBuilderTypes>(
data: APIMessageComponent & { type: T },
): MappedComponentBuilderTypes[T];
export function createComponentBuilder<C extends ComponentBuilder>(data: C): C;
export function createComponentBuilder(data: APIMessageComponent | ComponentBuilder): ComponentBuilder;
export class Formatters extends null { export class Formatters extends null {
public static blockQuote: typeof blockQuote; public static blockQuote: typeof blockQuote;
public static bold: typeof bold; public static bold: typeof bold;