feat: implement refineable

This commit is contained in:
didinele
2025-09-30 17:18:03 +03:00
parent a1c4501464
commit ff9b2ca14b
17 changed files with 61 additions and 28 deletions

View File

@@ -1,5 +1,6 @@
import type { JSONEncodable } from '@discordjs/util'; import type { JSONEncodable } from '@discordjs/util';
import type { APIBaseComponent, ComponentType } from 'discord-api-types/v10'; import type { APIBaseComponent, ComponentType } from 'discord-api-types/v10';
import { Refineable } from '../mixins/Refineable.js';
export interface ComponentBuilderBaseData { export interface ComponentBuilderBaseData {
id?: number | undefined; id?: number | undefined;
@@ -11,6 +12,7 @@ export interface ComponentBuilderBaseData {
* @typeParam Component - The type of API data that is stored within the builder * @typeParam Component - The type of API data that is stored within the builder
*/ */
export abstract class ComponentBuilder<Component extends APIBaseComponent<ComponentType>> export abstract class ComponentBuilder<Component extends APIBaseComponent<ComponentType>>
extends Refineable
implements JSONEncodable<Component> implements JSONEncodable<Component>
{ {
/** /**

View File

@@ -1,12 +1,13 @@
import type { JSONEncodable } from '@discordjs/util'; import type { JSONEncodable } from '@discordjs/util';
import type { APIMessageComponentEmoji, APISelectMenuOption } from 'discord-api-types/v10'; import type { APISelectMenuOption, APIMessageComponentEmoji } from 'discord-api-types/v10';
import { Refineable } from '../../mixins/Refineable.js';
import { validate } from '../../util/validation.js'; import { validate } from '../../util/validation.js';
import { selectMenuStringOptionPredicate } from '../Assertions.js'; import { selectMenuStringOptionPredicate } from '../Assertions.js';
/** /**
* A builder that creates API-compatible JSON data for string select menu options. * A builder that creates API-compatible JSON data for string select menu options.
*/ */
export class StringSelectMenuOptionBuilder implements JSONEncodable<APISelectMenuOption> { export class StringSelectMenuOptionBuilder extends Refineable implements JSONEncodable<APISelectMenuOption> {
private readonly data: Partial<APISelectMenuOption>; private readonly data: Partial<APISelectMenuOption>;
/** /**
@@ -32,6 +33,7 @@ export class StringSelectMenuOptionBuilder implements JSONEncodable<APISelectMen
* ``` * ```
*/ */
public constructor(data: Partial<APISelectMenuOption> = {}) { public constructor(data: Partial<APISelectMenuOption> = {}) {
super();
this.data = structuredClone(data); this.data = structuredClone(data);
} }

View File

@@ -1,9 +1,10 @@
import type { JSONEncodable } from '@discordjs/util'; import type { JSONEncodable } from '@discordjs/util';
import type { APIMediaGalleryItem } from 'discord-api-types/v10'; import type { APIMediaGalleryItem } from 'discord-api-types/v10';
import { Refineable } from '../../mixins/Refineable.js';
import { validate } from '../../util/validation.js'; import { validate } from '../../util/validation.js';
import { mediaGalleryItemPredicate } from './Assertions.js'; import { mediaGalleryItemPredicate } from './Assertions.js';
export class MediaGalleryItemBuilder implements JSONEncodable<APIMediaGalleryItem> { export class MediaGalleryItemBuilder extends Refineable implements JSONEncodable<APIMediaGalleryItem> {
private readonly data: Partial<APIMediaGalleryItem>; private readonly data: Partial<APIMediaGalleryItem>;
/** /**
@@ -32,6 +33,7 @@ export class MediaGalleryItemBuilder implements JSONEncodable<APIMediaGalleryIte
* ``` * ```
*/ */
public constructor(data: Partial<APIMediaGalleryItem> = {}) { public constructor(data: Partial<APIMediaGalleryItem> = {}) {
super();
this.data = structuredClone(data); this.data = structuredClone(data);
} }

View File

@@ -5,6 +5,7 @@ import type {
Permissions, Permissions,
RESTPostAPIApplicationCommandsJSONBody, RESTPostAPIApplicationCommandsJSONBody,
} from 'discord-api-types/v10'; } from 'discord-api-types/v10';
import { Refineable } from '../../mixins/Refineable.js';
import type { RestOrArray } from '../../util/normalizeArray.js'; import type { RestOrArray } from '../../util/normalizeArray.js';
import { normalizeArray } from '../../util/normalizeArray.js'; import { normalizeArray } from '../../util/normalizeArray.js';
@@ -20,6 +21,7 @@ export interface CommandData
* The base class for all command builders. * The base class for all command builders.
*/ */
export abstract class CommandBuilder<Command extends RESTPostAPIApplicationCommandsJSONBody> export abstract class CommandBuilder<Command extends RESTPostAPIApplicationCommandsJSONBody>
extends Refineable
implements JSONEncodable<Command> implements JSONEncodable<Command>
{ {
/** /**

View File

@@ -1,4 +1,5 @@
import type { Locale, RESTPostAPIApplicationCommandsJSONBody } from 'discord-api-types/v10'; import type { Locale, RESTPostAPIApplicationCommandsJSONBody } from 'discord-api-types/v10';
import { Refineable } from '../../mixins/Refineable.js';
export interface SharedNameData export interface SharedNameData
extends Partial<Pick<RESTPostAPIApplicationCommandsJSONBody, 'name_localizations' | 'name'>> {} extends Partial<Pick<RESTPostAPIApplicationCommandsJSONBody, 'name_localizations' | 'name'>> {}
@@ -6,7 +7,7 @@ export interface SharedNameData
/** /**
* This mixin holds name and description symbols for chat input commands. * This mixin holds name and description symbols for chat input commands.
*/ */
export class SharedName { export class SharedName extends Refineable {
/** /**
* @internal * @internal
*/ */

View File

@@ -9,6 +9,7 @@ import type { AnyModalComponentBuilder } from '../../components/Components.js';
import { createComponentBuilder } from '../../components/Components.js'; import { createComponentBuilder } from '../../components/Components.js';
import { LabelBuilder } from '../../components/label/Label.js'; import { LabelBuilder } from '../../components/label/Label.js';
import { TextDisplayBuilder } from '../../components/v2/TextDisplay.js'; import { TextDisplayBuilder } from '../../components/v2/TextDisplay.js';
import { Refineable } from '../../mixins/Refineable.js';
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js'; import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
import { resolveBuilder } from '../../util/resolveBuilder.js'; import { resolveBuilder } from '../../util/resolveBuilder.js';
import { validate } from '../../util/validation.js'; import { validate } from '../../util/validation.js';
@@ -21,7 +22,7 @@ export interface ModalBuilderData extends Partial<Omit<APIModalInteractionRespon
/** /**
* A builder that creates API-compatible JSON data for modals. * A builder that creates API-compatible JSON data for modals.
*/ */
export class ModalBuilder implements JSONEncodable<APIModalInteractionResponseCallbackData> { export class ModalBuilder extends Refineable implements JSONEncodable<APIModalInteractionResponseCallbackData> {
/** /**
* The API data associated with this modal. * The API data associated with this modal.
*/ */
@@ -40,6 +41,7 @@ export class ModalBuilder implements JSONEncodable<APIModalInteractionResponseCa
* @param data - The API data to create this modal with * @param data - The API data to create this modal with
*/ */
public constructor(data: Partial<APIModalInteractionResponseCallbackData> = {}) { public constructor(data: Partial<APIModalInteractionResponseCallbackData> = {}) {
super();
const { components = [], ...rest } = data; const { components = [], ...rest } = data;
this.data = { this.data = {

View File

@@ -1,5 +1,6 @@
import type { JSONEncodable } from '@discordjs/util'; import type { JSONEncodable } from '@discordjs/util';
import type { AllowedMentionsTypes, APIAllowedMentions, Snowflake } from 'discord-api-types/v10'; import type { AllowedMentionsTypes, APIAllowedMentions, Snowflake } from 'discord-api-types/v10';
import { Refineable } from '../mixins/Refineable.js';
import { normalizeArray, type RestOrArray } from '../util/normalizeArray.js'; import { normalizeArray, type RestOrArray } from '../util/normalizeArray.js';
import { validate } from '../util/validation.js'; import { validate } from '../util/validation.js';
import { allowedMentionPredicate } from './Assertions.js'; import { allowedMentionPredicate } from './Assertions.js';
@@ -7,7 +8,7 @@ import { allowedMentionPredicate } from './Assertions.js';
/** /**
* A builder that creates API-compatible JSON data for allowed mentions. * A builder that creates API-compatible JSON data for allowed mentions.
*/ */
export class AllowedMentionsBuilder implements JSONEncodable<APIAllowedMentions> { export class AllowedMentionsBuilder extends Refineable implements JSONEncodable<APIAllowedMentions> {
/** /**
* The API data associated with these allowed mentions. * The API data associated with these allowed mentions.
*/ */
@@ -19,7 +20,8 @@ export class AllowedMentionsBuilder implements JSONEncodable<APIAllowedMentions>
* @param data - The API data to create this allowed mentions with * @param data - The API data to create this allowed mentions with
*/ */
public constructor(data: Partial<APIAllowedMentions> = {}) { public constructor(data: Partial<APIAllowedMentions> = {}) {
this.data = structuredClone(data); super();
this.data = { ...structuredClone(data) };
} }
/** /**

View File

@@ -1,12 +1,13 @@
import type { JSONEncodable } from '@discordjs/util'; import type { JSONEncodable } from '@discordjs/util';
import type { RESTAPIAttachment, Snowflake } from 'discord-api-types/v10'; import type { RESTAPIAttachment, Snowflake } from 'discord-api-types/v10';
import { Refineable } from '../mixins/Refineable.js';
import { validate } from '../util/validation.js'; import { validate } from '../util/validation.js';
import { attachmentPredicate } from './Assertions.js'; import { attachmentPredicate } from './Assertions.js';
/** /**
* A builder that creates API-compatible JSON data for attachments. * A builder that creates API-compatible JSON data for attachments.
*/ */
export class AttachmentBuilder implements JSONEncodable<RESTAPIAttachment> { export class AttachmentBuilder extends Refineable implements JSONEncodable<RESTAPIAttachment> {
/** /**
* The API data associated with this attachment. * The API data associated with this attachment.
*/ */
@@ -15,10 +16,11 @@ export class AttachmentBuilder implements JSONEncodable<RESTAPIAttachment> {
/** /**
* Creates a new attachment builder. * Creates a new attachment builder.
* *
* @param data - The API data to create this attachment with * @param attachment - The attachment to build from
*/ */
public constructor(data: Partial<RESTAPIAttachment> = {}) { public constructor(attachment: Partial<RESTAPIAttachment> = {}) {
this.data = structuredClone(data); super();
this.data = { ...structuredClone(attachment) };
} }
/** /**

View File

@@ -28,6 +28,7 @@ import { MediaGalleryBuilder } from '../components/v2/MediaGallery.js';
import { SectionBuilder } from '../components/v2/Section.js'; import { SectionBuilder } from '../components/v2/Section.js';
import { SeparatorBuilder } from '../components/v2/Separator.js'; import { SeparatorBuilder } from '../components/v2/Separator.js';
import { TextDisplayBuilder } from '../components/v2/TextDisplay.js'; import { TextDisplayBuilder } from '../components/v2/TextDisplay.js';
import { Refineable } from '../mixins/Refineable.js';
import { normalizeArray, type RestOrArray } from '../util/normalizeArray.js'; import { normalizeArray, type RestOrArray } from '../util/normalizeArray.js';
import { resolveBuilder } from '../util/resolveBuilder.js'; import { resolveBuilder } from '../util/resolveBuilder.js';
import { validate } from '../util/validation.js'; import { validate } from '../util/validation.js';
@@ -56,7 +57,7 @@ export interface MessageBuilderData
/** /**
* A builder that creates API-compatible JSON data for messages. * A builder that creates API-compatible JSON data for messages.
*/ */
export class MessageBuilder implements JSONEncodable<RESTPostAPIChannelMessageJSONBody> { export class MessageBuilder extends Refineable implements JSONEncodable<RESTPostAPIChannelMessageJSONBody> {
/** /**
* The API data associated with this message. * The API data associated with this message.
*/ */
@@ -89,6 +90,7 @@ export class MessageBuilder implements JSONEncodable<RESTPostAPIChannelMessageJS
* @param data - The API data to create this message with * @param data - The API data to create this message with
*/ */
public constructor(data: Partial<RESTPostAPIChannelMessageJSONBody> = {}) { public constructor(data: Partial<RESTPostAPIChannelMessageJSONBody> = {}) {
super();
const { attachments = [], embeds = [], components = [], message_reference, poll, allowed_mentions, ...rest } = data; const { attachments = [], embeds = [], components = [], message_reference, poll, allowed_mentions, ...rest } = data;
this.data = { this.data = {

View File

@@ -1,12 +1,13 @@
import type { JSONEncodable } from '@discordjs/util'; import type { JSONEncodable } from '@discordjs/util';
import type { MessageReferenceType, RESTAPIMessageReference, Snowflake } from 'discord-api-types/v10'; import type { MessageReferenceType, RESTAPIMessageReference, Snowflake } from 'discord-api-types/v10';
import { Refineable } from '../mixins/Refineable.js';
import { validate } from '../util/validation.js'; import { validate } from '../util/validation.js';
import { messageReferencePredicate } from './Assertions.js'; import { messageReferencePredicate } from './Assertions.js';
/** /**
* A builder that creates API-compatible JSON data for message references. * A builder that creates API-compatible JSON data for message references.
*/ */
export class MessageReferenceBuilder implements JSONEncodable<RESTAPIMessageReference> { export class MessageReferenceBuilder extends Refineable implements JSONEncodable<RESTAPIMessageReference> {
/** /**
* The API data associated with this message reference. * The API data associated with this message reference.
*/ */
@@ -18,6 +19,7 @@ export class MessageReferenceBuilder implements JSONEncodable<RESTAPIMessageRefe
* @param data - The API data to create this message reference with * @param data - The API data to create this message reference with
*/ */
public constructor(data: Partial<RESTAPIMessageReference> = {}) { public constructor(data: Partial<RESTAPIMessageReference> = {}) {
super();
this.data = structuredClone(data); this.data = structuredClone(data);
} }

View File

@@ -1,5 +1,6 @@
import type { JSONEncodable } from '@discordjs/util'; import type { JSONEncodable } from '@discordjs/util';
import type { APIEmbed, APIEmbedAuthor, APIEmbedField, APIEmbedFooter } from 'discord-api-types/v10'; import type { APIEmbed, APIEmbedAuthor, APIEmbedField, APIEmbedFooter } from 'discord-api-types/v10';
import { Refineable } from '../../mixins/Refineable.js';
import type { RestOrArray } from '../../util/normalizeArray.js'; import type { RestOrArray } from '../../util/normalizeArray.js';
import { normalizeArray } from '../../util/normalizeArray.js'; import { normalizeArray } from '../../util/normalizeArray.js';
import { resolveBuilder } from '../../util/resolveBuilder.js'; import { resolveBuilder } from '../../util/resolveBuilder.js';
@@ -21,7 +22,7 @@ export interface EmbedBuilderData extends Omit<APIEmbed, 'author' | 'fields' | '
/** /**
* A builder that creates API-compatible JSON data for embeds. * A builder that creates API-compatible JSON data for embeds.
*/ */
export class EmbedBuilder implements JSONEncodable<APIEmbed> { export class EmbedBuilder extends Refineable implements JSONEncodable<APIEmbed> {
/** /**
* The API data associated with this embed. * The API data associated with this embed.
*/ */
@@ -40,6 +41,7 @@ export class EmbedBuilder implements JSONEncodable<APIEmbed> {
* @param data - The API data to create this embed with * @param data - The API data to create this embed with
*/ */
public constructor(data: Partial<APIEmbed> = {}) { public constructor(data: Partial<APIEmbed> = {}) {
super();
const { author, fields = [], footer, ...rest } = data; const { author, fields = [], footer, ...rest } = data;
this.data = { this.data = {

View File

@@ -1,24 +1,26 @@
import type { JSONEncodable } from '@discordjs/util'; import type { JSONEncodable } from '@discordjs/util';
import type { APIEmbedAuthor } from 'discord-api-types/v10'; import type { APIEmbedAuthor } from 'discord-api-types/v10';
import { Refineable } from '../../mixins/Refineable.js';
import { validate } from '../../util/validation.js'; import { validate } from '../../util/validation.js';
import { embedAuthorPredicate } from './Assertions.js'; import { embedAuthorPredicate } from './Assertions.js';
/** /**
* A builder that creates API-compatible JSON data for the embed author. * A builder that creates API-compatible JSON data for embed authors.
*/ */
export class EmbedAuthorBuilder implements JSONEncodable<APIEmbedAuthor> { export class EmbedAuthorBuilder extends Refineable implements JSONEncodable<APIEmbedAuthor> {
/** /**
* The API data associated with this embed author. * The API data associated with this embed author.
*/ */
private readonly data: Partial<APIEmbedAuthor>; private readonly data: Partial<APIEmbedAuthor>;
/** /**
* Creates a new embed author. * Creates a new embed author builder.
* *
* @param data - The API data to create this embed author with * @param data - The API data to create this embed author with
*/ */
public constructor(data: Partial<APIEmbedAuthor> = {}) { public constructor(data: Partial<APIEmbedAuthor> = {}) {
this.data = structuredClone(data); super();
this.data = { ...structuredClone(data) };
} }
/** /**

View File

@@ -1,24 +1,26 @@
import type { JSONEncodable } from '@discordjs/util'; import type { JSONEncodable } from '@discordjs/util';
import type { APIEmbedField } from 'discord-api-types/v10'; import type { APIEmbedField } from 'discord-api-types/v10';
import { Refineable } from '../../mixins/Refineable.js';
import { validate } from '../../util/validation.js'; import { validate } from '../../util/validation.js';
import { embedFieldPredicate } from './Assertions.js'; import { embedFieldPredicate } from './Assertions.js';
/** /**
* A builder that creates API-compatible JSON data for embed fields. * A builder that creates API-compatible JSON data for embed fields.
*/ */
export class EmbedFieldBuilder implements JSONEncodable<APIEmbedField> { export class EmbedFieldBuilder extends Refineable implements JSONEncodable<APIEmbedField> {
/** /**
* The API data associated with this embed field. * The API data associated with this embed field.
*/ */
private readonly data: Partial<APIEmbedField>; private readonly data: Partial<APIEmbedField>;
/** /**
* Creates a new embed field. * Creates a new embed field builder.
* *
* @param data - The API data to create this embed field with * @param data - The API data to create this embed field with
*/ */
public constructor(data: Partial<APIEmbedField> = {}) { public constructor(data: Partial<APIEmbedField> = {}) {
this.data = structuredClone(data); super();
this.data = { ...structuredClone(data) };
} }
/** /**

View File

@@ -1,24 +1,26 @@
import type { JSONEncodable } from '@discordjs/util'; import type { JSONEncodable } from '@discordjs/util';
import type { APIEmbedFooter } from 'discord-api-types/v10'; import type { APIEmbedFooter } from 'discord-api-types/v10';
import { Refineable } from '../../mixins/Refineable.js';
import { validate } from '../../util/validation.js'; import { validate } from '../../util/validation.js';
import { embedFooterPredicate } from './Assertions.js'; import { embedFooterPredicate } from './Assertions.js';
/** /**
* A builder that creates API-compatible JSON data for the embed footer. * A builder that creates API-compatible JSON data for embed footers.
*/ */
export class EmbedFooterBuilder implements JSONEncodable<APIEmbedFooter> { export class EmbedFooterBuilder extends Refineable implements JSONEncodable<APIEmbedFooter> {
/** /**
* The API data associated with this embed footer. * The API data associated with this embed footer.
*/ */
private readonly data: Partial<APIEmbedFooter>; private readonly data: Partial<APIEmbedFooter>;
/** /**
* Creates a new embed footer. * Creates a new embed footer builder.
* *
* @param data - The API data to create this embed footer with * @param data - The API data to create this embed footer with
*/ */
public constructor(data: Partial<APIEmbedFooter> = {}) { public constructor(data: Partial<APIEmbedFooter> = {}) {
this.data = structuredClone(data); super();
this.data = { ...structuredClone(data) };
} }
/** /**

View File

@@ -1,5 +1,6 @@
import type { JSONEncodable } from '@discordjs/util'; import type { JSONEncodable } from '@discordjs/util';
import type { RESTAPIPoll, APIPollMedia, PollLayoutType, APIPollAnswer } from 'discord-api-types/v10'; import type { RESTAPIPoll, APIPollMedia, PollLayoutType, APIPollAnswer } from 'discord-api-types/v10';
import { Refineable } from '../../mixins/Refineable.js';
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js'; import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
import { resolveBuilder } from '../../util/resolveBuilder.js'; import { resolveBuilder } from '../../util/resolveBuilder.js';
import { validate } from '../../util/validation.js'; import { validate } from '../../util/validation.js';
@@ -15,7 +16,7 @@ export interface PollData extends Omit<RESTAPIPoll, 'answers' | 'question'> {
/** /**
* A builder that creates API-compatible JSON data for polls. * A builder that creates API-compatible JSON data for polls.
*/ */
export class PollBuilder implements JSONEncodable<RESTAPIPoll> { export class PollBuilder extends Refineable implements JSONEncodable<RESTAPIPoll> {
/** /**
* The API data associated with this poll. * The API data associated with this poll.
*/ */
@@ -34,6 +35,7 @@ export class PollBuilder implements JSONEncodable<RESTAPIPoll> {
* @param data - The API data to create this poll with * @param data - The API data to create this poll with
*/ */
public constructor(data: Partial<RESTAPIPoll> = {}) { public constructor(data: Partial<RESTAPIPoll> = {}) {
super();
const { question, answers = [], ...rest } = data; const { question, answers = [], ...rest } = data;
this.data = { this.data = {

View File

@@ -1,5 +1,6 @@
import type { JSONEncodable } from '@discordjs/util'; import type { JSONEncodable } from '@discordjs/util';
import type { APIPollAnswer, APIPollMedia } from 'discord-api-types/v10'; import type { APIPollAnswer, APIPollMedia } from 'discord-api-types/v10';
import { Refineable } from '../../mixins/Refineable.js';
import { resolveBuilder } from '../../util/resolveBuilder'; import { resolveBuilder } from '../../util/resolveBuilder';
import { validate } from '../../util/validation'; import { validate } from '../../util/validation';
import { pollAnswerPredicate } from './Assertions'; import { pollAnswerPredicate } from './Assertions';
@@ -12,7 +13,7 @@ export interface PollAnswerData extends Omit<APIPollAnswer, 'answer_id' | 'poll_
/** /**
* A builder that creates API-compatible JSON data for poll answers. * A builder that creates API-compatible JSON data for poll answers.
*/ */
export class PollAnswerBuilder implements JSONEncodable<Omit<APIPollAnswer, 'answer_id'>> { export class PollAnswerBuilder extends Refineable implements JSONEncodable<Omit<APIPollAnswer, 'answer_id'>> {
/** /**
* The API data associated with this poll answer. * The API data associated with this poll answer.
*/ */
@@ -24,6 +25,7 @@ export class PollAnswerBuilder implements JSONEncodable<Omit<APIPollAnswer, 'ans
* @param data - The API data to create this poll answer with * @param data - The API data to create this poll answer with
*/ */
public constructor(data: Partial<Omit<APIPollAnswer, 'answer_id'>> = {}) { public constructor(data: Partial<Omit<APIPollAnswer, 'answer_id'>> = {}) {
super();
const { poll_media, ...rest } = data; const { poll_media, ...rest } = data;
this.data = { this.data = {

View File

@@ -1,9 +1,10 @@
import type { APIPollMedia } from 'discord-api-types/v10'; import type { APIPollMedia } from 'discord-api-types/v10';
import { Refineable } from '../../mixins/Refineable.js';
/** /**
* The base poll media builder that contains common symbols for poll media builders. * The base poll media builder that contains common symbols for poll media builders.
*/ */
export abstract class PollMediaBuilder { export abstract class PollMediaBuilder extends Refineable {
/** /**
* The API data associated with this poll media. * The API data associated with this poll media.
* *
@@ -17,6 +18,7 @@ export abstract class PollMediaBuilder {
* @param data - The API data to create this poll media with * @param data - The API data to create this poll media with
*/ */
public constructor(data: Partial<APIPollMedia> = {}) { public constructor(data: Partial<APIPollMedia> = {}) {
super();
this.data = structuredClone(data); this.data = structuredClone(data);
} }