mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-17 03:53:29 +01:00
refactor: replace zod with shapeshift (#7547)
This commit is contained in:
@@ -101,10 +101,10 @@ describe('Embed', () => {
|
|||||||
expect(embed.toJSON()).toStrictEqual({ url: undefined });
|
expect(embed.toJSON()).toStrictEqual({ url: undefined });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN an embed with an invalid URL THEN throws error', () => {
|
test.each(['owo', 'discord://user'])('GIVEN an embed with an invalid URL THEN throws error', (input) => {
|
||||||
const embed = new EmbedBuilder();
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
expect(() => embed.setURL('owo')).toThrowError();
|
expect(() => embed.setURL(input)).toThrowError();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -325,7 +325,7 @@ describe('Embed', () => {
|
|||||||
embed.addFields({ name: 'foo', value: 'bar' });
|
embed.addFields({ name: 'foo', value: 'bar' });
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
fields: [{ name: 'foo', value: 'bar' }],
|
fields: [{ name: 'foo', value: 'bar', inline: undefined }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -334,7 +334,7 @@ describe('Embed', () => {
|
|||||||
embed.addFields({ name: 'foo', value: 'bar' }, { name: 'foo', value: 'baz' });
|
embed.addFields({ name: 'foo', value: 'bar' }, { name: 'foo', value: 'baz' });
|
||||||
|
|
||||||
expect(embed.spliceFields(0, 1).toJSON()).toStrictEqual({
|
expect(embed.spliceFields(0, 1).toJSON()).toStrictEqual({
|
||||||
fields: [{ name: 'foo', value: 'baz' }],
|
fields: [{ name: 'foo', value: 'baz', inline: undefined }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -52,12 +52,12 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://discord.js.org",
|
"homepage": "https://discord.js.org",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@sapphire/shapeshift": "^2.0.0",
|
||||||
"@sindresorhus/is": "^4.4.0",
|
"@sindresorhus/is": "^4.4.0",
|
||||||
"discord-api-types": "^0.29.0",
|
"discord-api-types": "^0.29.0",
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
"ts-mixer": "^6.0.0",
|
"ts-mixer": "^6.0.0",
|
||||||
"tslib": "^2.3.1",
|
"tslib": "^2.3.1"
|
||||||
"zod": "^3.11.6"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.17.2",
|
"@babel/core": "^7.17.2",
|
||||||
|
|||||||
@@ -1,56 +1,55 @@
|
|||||||
import { APIMessageComponentEmoji, ButtonStyle } from 'discord-api-types/v10';
|
import { APIMessageComponentEmoji, ButtonStyle } from 'discord-api-types/v10';
|
||||||
import { z } from 'zod';
|
import { s } from '@sapphire/shapeshift';
|
||||||
import type { SelectMenuOptionBuilder } from './selectMenu/SelectMenuOption';
|
import type { SelectMenuOptionBuilder } from './selectMenu/SelectMenuOption';
|
||||||
import { UnsafeSelectMenuOptionBuilder } from './selectMenu/UnsafeSelectMenuOption';
|
import { UnsafeSelectMenuOptionBuilder } from './selectMenu/UnsafeSelectMenuOption';
|
||||||
|
|
||||||
export const customIdValidator = z.string().min(1).max(100);
|
export const customIdValidator = s.string.lengthGe(1).lengthLe(100);
|
||||||
|
|
||||||
export const emojiValidator = z
|
export const emojiValidator = s.object({
|
||||||
.object({
|
id: s.string,
|
||||||
id: z.string(),
|
name: s.string,
|
||||||
name: z.string(),
|
animated: s.boolean,
|
||||||
animated: z.boolean(),
|
}).partial.strict;
|
||||||
})
|
|
||||||
.partial()
|
|
||||||
.strict();
|
|
||||||
|
|
||||||
export const disabledValidator = z.boolean();
|
export const disabledValidator = s.boolean;
|
||||||
|
|
||||||
export const buttonLabelValidator = z.string().nonempty().max(80);
|
export const buttonLabelValidator = s.string.lengthGe(1).lengthLe(80);
|
||||||
|
|
||||||
export const buttonStyleValidator = z.number().int().min(ButtonStyle.Primary).max(ButtonStyle.Link);
|
export const buttonStyleValidator = s.nativeEnum(ButtonStyle);
|
||||||
|
|
||||||
export const placeholderValidator = z.string().max(150);
|
export const placeholderValidator = s.string.lengthLe(150);
|
||||||
export const minMaxValidator = z.number().int().min(0).max(25);
|
export const minMaxValidator = s.number.int.ge(0).le(25);
|
||||||
|
|
||||||
export const labelValueDescriptionValidator = z.string().min(1).max(100);
|
export const labelValueDescriptionValidator = s.string.lengthGe(1).lengthLe(100);
|
||||||
export const optionValidator = z.union([
|
export const optionValidator = s.union(
|
||||||
z.object({
|
s.object({
|
||||||
label: labelValueDescriptionValidator,
|
label: labelValueDescriptionValidator,
|
||||||
value: labelValueDescriptionValidator,
|
value: labelValueDescriptionValidator,
|
||||||
description: labelValueDescriptionValidator.optional(),
|
description: labelValueDescriptionValidator.optional,
|
||||||
emoji: emojiValidator.optional(),
|
emoji: emojiValidator.optional,
|
||||||
default: z.boolean().optional(),
|
default: s.boolean.optional,
|
||||||
}),
|
}),
|
||||||
z.instanceof(UnsafeSelectMenuOptionBuilder),
|
s.instance(UnsafeSelectMenuOptionBuilder),
|
||||||
]);
|
);
|
||||||
export const optionsValidator = optionValidator.array().nonempty();
|
export const optionsValidator = optionValidator.array.lengthGe(0);
|
||||||
export const optionsLengthValidator = z.number().int().min(0).max(25);
|
export const optionsLengthValidator = s.number.int.ge(0).le(25);
|
||||||
|
|
||||||
export function validateRequiredSelectMenuParameters(options: SelectMenuOptionBuilder[], customId?: string) {
|
export function validateRequiredSelectMenuParameters(options: SelectMenuOptionBuilder[], customId?: string) {
|
||||||
customIdValidator.parse(customId);
|
customIdValidator.parse(customId);
|
||||||
optionsValidator.parse(options);
|
optionsValidator.parse(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const labelValueValidator = z.string().min(1).max(100);
|
export const labelValueValidator = s.string.lengthGe(1).lengthLe(100);
|
||||||
export const defaultValidator = z.boolean();
|
export const defaultValidator = s.boolean;
|
||||||
|
|
||||||
export function validateRequiredSelectMenuOptionParameters(label?: string, value?: string) {
|
export function validateRequiredSelectMenuOptionParameters(label?: string, value?: string) {
|
||||||
labelValueValidator.parse(label);
|
labelValueValidator.parse(label);
|
||||||
labelValueValidator.parse(value);
|
labelValueValidator.parse(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const urlValidator = z.string().url();
|
export const urlValidator = s.string.url({
|
||||||
|
allowedProtocols: ['http:', 'https:', 'discord:'],
|
||||||
|
});
|
||||||
|
|
||||||
export function validateRequiredButtonParameters(
|
export function validateRequiredButtonParameters(
|
||||||
style?: ButtonStyle,
|
style?: ButtonStyle,
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { TextInputStyle } from 'discord-api-types/v10';
|
import { TextInputStyle } from 'discord-api-types/v10';
|
||||||
import { z } from 'zod';
|
import { s } from '@sapphire/shapeshift';
|
||||||
import { customIdValidator } from '../Assertions';
|
import { customIdValidator } from '../Assertions';
|
||||||
|
|
||||||
export const textInputStyleValidator = z.nativeEnum(TextInputStyle);
|
export const textInputStyleValidator = s.nativeEnum(TextInputStyle);
|
||||||
export const minLengthValidator = z.number().int().min(0).max(4000);
|
export const minLengthValidator = s.number.int.ge(0).le(4000);
|
||||||
export const maxLengthValidator = z.number().int().min(1).max(4000);
|
export const maxLengthValidator = s.number.int.ge(1).le(4000);
|
||||||
export const requiredValidator = z.boolean();
|
export const requiredValidator = s.boolean;
|
||||||
export const valueValidator = z.string().max(4000);
|
export const valueValidator = s.string.lengthLe(4000);
|
||||||
export const placeholderValidator = z.string().max(100);
|
export const placeholderValidator = s.string.lengthLe(100);
|
||||||
export const labelValidator = z.string().min(1).max(45);
|
export const labelValidator = s.string.lengthGe(1).lengthLe(45);
|
||||||
|
|
||||||
export function validateRequiredParameters(customId?: string, style?: TextInputStyle, label?: string) {
|
export function validateRequiredParameters(customId?: string, style?: TextInputStyle, label?: string) {
|
||||||
customIdValidator.parse(customId);
|
customIdValidator.parse(customId);
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
import { z } from 'zod';
|
import { s } from '@sapphire/shapeshift';
|
||||||
import { ApplicationCommandType } from 'discord-api-types/v10';
|
import { ApplicationCommandType } from 'discord-api-types/v10';
|
||||||
import type { ContextMenuCommandType } from './ContextMenuCommandBuilder';
|
import type { ContextMenuCommandType } from './ContextMenuCommandBuilder';
|
||||||
|
|
||||||
const namePredicate = z
|
const namePredicate = s.string
|
||||||
.string()
|
.lengthGe(1)
|
||||||
.min(1)
|
.lengthLe(32)
|
||||||
.max(32)
|
|
||||||
.regex(/^( *[\p{L}\p{N}_-]+ *)+$/u);
|
.regex(/^( *[\p{L}\p{N}_-]+ *)+$/u);
|
||||||
|
|
||||||
const typePredicate = z.union([z.literal(ApplicationCommandType.User), z.literal(ApplicationCommandType.Message)]);
|
const typePredicate = s.union(s.literal(ApplicationCommandType.User), s.literal(ApplicationCommandType.Message));
|
||||||
|
|
||||||
const booleanPredicate = z.boolean();
|
const booleanPredicate = s.boolean;
|
||||||
|
|
||||||
export function validateDefaultPermission(value: unknown): asserts value is boolean {
|
export function validateDefaultPermission(value: unknown): asserts value is boolean {
|
||||||
booleanPredicate.parse(value);
|
booleanPredicate.parse(value);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { z } from 'zod';
|
import { s } from '@sapphire/shapeshift';
|
||||||
import { ActionRowBuilder, type ModalActionRowComponentBuilder } from '../..';
|
import { ActionRowBuilder, type ModalActionRowComponentBuilder } from '../..';
|
||||||
import { customIdValidator } from '../../components/Assertions';
|
import { customIdValidator } from '../../components/Assertions';
|
||||||
|
|
||||||
export const titleValidator = z.string().min(1).max(45);
|
export const titleValidator = s.string.lengthGe(1).lengthLe(45);
|
||||||
export const componentsValidator = z.array(z.instanceof(ActionRowBuilder)).min(1);
|
export const componentsValidator = s.instance(ActionRowBuilder).array.lengthGe(1);
|
||||||
|
|
||||||
export function validateRequiredParameters(
|
export function validateRequiredParameters(
|
||||||
customId?: string,
|
customId?: string,
|
||||||
|
|||||||
@@ -1,27 +1,26 @@
|
|||||||
import is from '@sindresorhus/is';
|
import is from '@sindresorhus/is';
|
||||||
import type { APIApplicationCommandOptionChoice } from 'discord-api-types/v10';
|
import type { APIApplicationCommandOptionChoice } from 'discord-api-types/v10';
|
||||||
import { z } from 'zod';
|
import { s } from '@sapphire/shapeshift';
|
||||||
import type { ApplicationCommandOptionBase } from './mixins/ApplicationCommandOptionBase';
|
import type { ApplicationCommandOptionBase } from './mixins/ApplicationCommandOptionBase';
|
||||||
import type { ToAPIApplicationCommandOptions } from './SlashCommandBuilder';
|
import type { ToAPIApplicationCommandOptions } from './SlashCommandBuilder';
|
||||||
import type { SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder } from './SlashCommandSubcommands';
|
import type { SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder } from './SlashCommandSubcommands';
|
||||||
|
|
||||||
const namePredicate = z
|
const namePredicate = s.string
|
||||||
.string()
|
.lengthGe(1)
|
||||||
.min(1)
|
.lengthLe(32)
|
||||||
.max(32)
|
|
||||||
.regex(/^[\P{Lu}\p{N}_-]+$/u);
|
.regex(/^[\P{Lu}\p{N}_-]+$/u);
|
||||||
|
|
||||||
export function validateName(name: unknown): asserts name is string {
|
export function validateName(name: unknown): asserts name is string {
|
||||||
namePredicate.parse(name);
|
namePredicate.parse(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
const descriptionPredicate = z.string().min(1).max(100);
|
const descriptionPredicate = s.string.lengthGe(1).lengthLe(100);
|
||||||
|
|
||||||
export function validateDescription(description: unknown): asserts description is string {
|
export function validateDescription(description: unknown): asserts description is string {
|
||||||
descriptionPredicate.parse(description);
|
descriptionPredicate.parse(description);
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxArrayLengthPredicate = z.unknown().array().max(25);
|
const maxArrayLengthPredicate = s.unknown.array.lengthLe(25);
|
||||||
|
|
||||||
export function validateMaxOptionsLength(options: unknown): asserts options is ToAPIApplicationCommandOptions[] {
|
export function validateMaxOptionsLength(options: unknown): asserts options is ToAPIApplicationCommandOptions[] {
|
||||||
maxArrayLengthPredicate.parse(options);
|
maxArrayLengthPredicate.parse(options);
|
||||||
@@ -42,7 +41,7 @@ export function validateRequiredParameters(
|
|||||||
validateMaxOptionsLength(options);
|
validateMaxOptionsLength(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
const booleanPredicate = z.boolean();
|
const booleanPredicate = s.boolean;
|
||||||
|
|
||||||
export function validateDefaultPermission(value: unknown): asserts value is boolean {
|
export function validateDefaultPermission(value: unknown): asserts value is boolean {
|
||||||
booleanPredicate.parse(value);
|
booleanPredicate.parse(value);
|
||||||
@@ -52,7 +51,7 @@ export function validateRequired(required: unknown): asserts required is boolean
|
|||||||
booleanPredicate.parse(required);
|
booleanPredicate.parse(required);
|
||||||
}
|
}
|
||||||
|
|
||||||
const choicesLengthPredicate = z.number().lte(25);
|
const choicesLengthPredicate = s.number.le(25);
|
||||||
|
|
||||||
export function validateChoicesLength(amountAdding: number, choices?: APIApplicationCommandOptionChoice[]): void {
|
export function validateChoicesLength(amountAdding: number, choices?: APIApplicationCommandOptionChoice[]): void {
|
||||||
choicesLengthPredicate.parse((choices?.length ?? 0) + amountAdding);
|
choicesLengthPredicate.parse((choices?.length ?? 0) + amountAdding);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ChannelType } from 'discord-api-types/v10';
|
import { ChannelType } from 'discord-api-types/v10';
|
||||||
import { z, ZodLiteral } from 'zod';
|
import { s } from '@sapphire/shapeshift';
|
||||||
|
|
||||||
// Only allow valid channel types to be used. (This can't be dynamic because const enums are erased at runtime)
|
// Only allow valid channel types to be used. (This can't be dynamic because const enums are erased at runtime)
|
||||||
const allowedChannelTypes = [
|
const allowedChannelTypes = [
|
||||||
@@ -15,15 +15,7 @@ const allowedChannelTypes = [
|
|||||||
|
|
||||||
export type ApplicationCommandOptionAllowedChannelTypes = typeof allowedChannelTypes[number];
|
export type ApplicationCommandOptionAllowedChannelTypes = typeof allowedChannelTypes[number];
|
||||||
|
|
||||||
const channelTypesPredicate = z.array(
|
const channelTypesPredicate = s.array(s.union(...allowedChannelTypes.map((type) => s.literal(type))));
|
||||||
z.union(
|
|
||||||
allowedChannelTypes.map((type) => z.literal(type)) as [
|
|
||||||
ZodLiteral<ChannelType>,
|
|
||||||
ZodLiteral<ChannelType>,
|
|
||||||
...ZodLiteral<ChannelType>[]
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
export class ApplicationCommandOptionChannelTypesMixin {
|
export class ApplicationCommandOptionChannelTypesMixin {
|
||||||
public readonly channel_types?: ApplicationCommandOptionAllowedChannelTypes[];
|
public readonly channel_types?: ApplicationCommandOptionAllowedChannelTypes[];
|
||||||
@@ -38,9 +30,7 @@ export class ApplicationCommandOptionChannelTypesMixin {
|
|||||||
Reflect.set(this, 'channel_types', []);
|
Reflect.set(this, 'channel_types', []);
|
||||||
}
|
}
|
||||||
|
|
||||||
channelTypesPredicate.parse(channelTypes);
|
this.channel_types!.push(...channelTypesPredicate.parse(channelTypes));
|
||||||
|
|
||||||
this.channel_types!.push(...channelTypes);
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
import { APIApplicationCommandOptionChoice, ApplicationCommandOptionType } from 'discord-api-types/v10';
|
import { APIApplicationCommandOptionChoice, ApplicationCommandOptionType } from 'discord-api-types/v10';
|
||||||
import { z } from 'zod';
|
import { s } from '@sapphire/shapeshift';
|
||||||
import { validateChoicesLength } from '../Assertions';
|
import { validateChoicesLength } from '../Assertions';
|
||||||
|
|
||||||
const stringPredicate = z.string().min(1).max(100);
|
const stringPredicate = s.string.lengthGe(1).lengthLe(100);
|
||||||
const numberPredicate = z.number().gt(-Infinity).lt(Infinity);
|
const numberPredicate = s.number.gt(-Infinity).lt(Infinity);
|
||||||
const choicesPredicate = z
|
const choicesPredicate = s.object({ name: stringPredicate, value: s.union(stringPredicate, numberPredicate) }).array;
|
||||||
.object({ name: stringPredicate, value: z.union([stringPredicate, numberPredicate]) })
|
const booleanPredicate = s.boolean;
|
||||||
.array();
|
|
||||||
const booleanPredicate = z.boolean();
|
|
||||||
|
|
||||||
export class ApplicationCommandOptionWithChoicesAndAutocompleteMixin<T extends string | number> {
|
export class ApplicationCommandOptionWithChoicesAndAutocompleteMixin<T extends string | number> {
|
||||||
public readonly choices?: APIApplicationCommandOptionChoice<T>[];
|
public readonly choices?: APIApplicationCommandOptionChoice<T>[];
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { APIApplicationCommandIntegerOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
|
import { APIApplicationCommandIntegerOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
|
||||||
import { mix } from 'ts-mixer';
|
import { mix } from 'ts-mixer';
|
||||||
import { z } from 'zod';
|
import { s } from '@sapphire/shapeshift';
|
||||||
import { ApplicationCommandNumericOptionMinMaxValueMixin } from '../mixins/ApplicationCommandNumericOptionMinMaxValueMixin';
|
import { ApplicationCommandNumericOptionMinMaxValueMixin } from '../mixins/ApplicationCommandNumericOptionMinMaxValueMixin';
|
||||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
|
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
|
||||||
import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin';
|
import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin';
|
||||||
|
|
||||||
const numberValidator = z.number().int();
|
const numberValidator = s.number.int;
|
||||||
|
|
||||||
@mix(ApplicationCommandNumericOptionMinMaxValueMixin, ApplicationCommandOptionWithChoicesAndAutocompleteMixin)
|
@mix(ApplicationCommandNumericOptionMinMaxValueMixin, ApplicationCommandOptionWithChoicesAndAutocompleteMixin)
|
||||||
export class SlashCommandIntegerOption
|
export class SlashCommandIntegerOption
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { APIApplicationCommandNumberOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
|
import { APIApplicationCommandNumberOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
|
||||||
import { mix } from 'ts-mixer';
|
import { mix } from 'ts-mixer';
|
||||||
import { z } from 'zod';
|
import { s } from '@sapphire/shapeshift';
|
||||||
import { ApplicationCommandNumericOptionMinMaxValueMixin } from '../mixins/ApplicationCommandNumericOptionMinMaxValueMixin';
|
import { ApplicationCommandNumericOptionMinMaxValueMixin } from '../mixins/ApplicationCommandNumericOptionMinMaxValueMixin';
|
||||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
|
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
|
||||||
import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin';
|
import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin';
|
||||||
|
|
||||||
const numberValidator = z.number();
|
const numberValidator = s.number;
|
||||||
|
|
||||||
@mix(ApplicationCommandNumericOptionMinMaxValueMixin, ApplicationCommandOptionWithChoicesAndAutocompleteMixin)
|
@mix(ApplicationCommandNumericOptionMinMaxValueMixin, ApplicationCommandOptionWithChoicesAndAutocompleteMixin)
|
||||||
export class SlashCommandNumberOption
|
export class SlashCommandNumberOption
|
||||||
|
|||||||
@@ -1,43 +1,46 @@
|
|||||||
import type { APIEmbedField } from 'discord-api-types/v10';
|
import type { APIEmbedField } from 'discord-api-types/v10';
|
||||||
import { z } from 'zod';
|
import { s } from '@sapphire/shapeshift';
|
||||||
|
|
||||||
export const fieldNamePredicate = z.string().min(1).max(256);
|
export const fieldNamePredicate = s.string.lengthGe(1).lengthLe(256);
|
||||||
|
|
||||||
export const fieldValuePredicate = z.string().min(1).max(1024);
|
export const fieldValuePredicate = s.string.lengthGe(1).lengthLe(1024);
|
||||||
|
|
||||||
export const fieldInlinePredicate = z.boolean().optional();
|
export const fieldInlinePredicate = s.boolean.optional;
|
||||||
|
|
||||||
export const embedFieldPredicate = z.object({
|
export const embedFieldPredicate = s.object({
|
||||||
name: fieldNamePredicate,
|
name: fieldNamePredicate,
|
||||||
value: fieldValuePredicate,
|
value: fieldValuePredicate,
|
||||||
inline: fieldInlinePredicate,
|
inline: fieldInlinePredicate,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const embedFieldsArrayPredicate = embedFieldPredicate.array();
|
export const embedFieldsArrayPredicate = embedFieldPredicate.array;
|
||||||
|
|
||||||
export const fieldLengthPredicate = z.number().lte(25);
|
export const fieldLengthPredicate = s.number.le(25);
|
||||||
|
|
||||||
export function validateFieldLength(amountAdding: number, fields?: APIEmbedField[]): void {
|
export function validateFieldLength(amountAdding: number, fields?: APIEmbedField[]): void {
|
||||||
fieldLengthPredicate.parse((fields?.length ?? 0) + amountAdding);
|
fieldLengthPredicate.parse((fields?.length ?? 0) + amountAdding);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const authorNamePredicate = fieldNamePredicate.nullable();
|
export const authorNamePredicate = fieldNamePredicate.nullable;
|
||||||
|
|
||||||
export const urlPredicate = z.string().url().nullish();
|
export const imageURLPredicate = s.string.url({
|
||||||
|
allowedProtocols: ['http:', 'https:', 'attachment:'],
|
||||||
|
}).nullish;
|
||||||
|
|
||||||
export const RGBPredicate = z.number().int().gte(0).lte(255);
|
export const urlPredicate = s.string.url({
|
||||||
export const colorPredicate = z
|
allowedProtocols: ['http:', 'https:'],
|
||||||
.number()
|
}).nullish;
|
||||||
.int()
|
|
||||||
.gte(0)
|
|
||||||
.lte(0xffffff)
|
|
||||||
.nullable()
|
|
||||||
.or(z.tuple([RGBPredicate, RGBPredicate, RGBPredicate]));
|
|
||||||
|
|
||||||
export const descriptionPredicate = z.string().min(1).max(4096).nullable();
|
export const RGBPredicate = s.number.int.ge(0).le(255);
|
||||||
|
export const colorPredicate = s.number.int
|
||||||
|
.ge(0)
|
||||||
|
.le(0xffffff)
|
||||||
|
.or(s.tuple([RGBPredicate, RGBPredicate, RGBPredicate])).nullable;
|
||||||
|
|
||||||
export const footerTextPredicate = z.string().min(1).max(2048).nullable();
|
export const descriptionPredicate = s.string.lengthGe(1).lengthLe(4096).nullable;
|
||||||
|
|
||||||
export const timestampPredicate = z.union([z.number(), z.date()]).nullable();
|
export const footerTextPredicate = s.string.lengthGe(1).lengthLe(2048).nullable;
|
||||||
|
|
||||||
export const titlePredicate = fieldNamePredicate.nullable();
|
export const timestampPredicate = s.union(s.number, s.date).nullable;
|
||||||
|
|
||||||
|
export const titlePredicate = fieldNamePredicate.nullable;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
descriptionPredicate,
|
descriptionPredicate,
|
||||||
embedFieldsArrayPredicate,
|
embedFieldsArrayPredicate,
|
||||||
footerTextPredicate,
|
footerTextPredicate,
|
||||||
|
imageURLPredicate,
|
||||||
timestampPredicate,
|
timestampPredicate,
|
||||||
titlePredicate,
|
titlePredicate,
|
||||||
urlPredicate,
|
urlPredicate,
|
||||||
@@ -69,12 +70,12 @@ export class EmbedBuilder extends UnsafeEmbedBuilder {
|
|||||||
|
|
||||||
public override setImage(url: string | null): this {
|
public override setImage(url: string | null): this {
|
||||||
// Data assertions
|
// Data assertions
|
||||||
return super.setImage(urlPredicate.parse(url)!);
|
return super.setImage(imageURLPredicate.parse(url)!);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override setThumbnail(url: string | null): this {
|
public override setThumbnail(url: string | null): this {
|
||||||
// Data assertions
|
// Data assertions
|
||||||
return super.setThumbnail(urlPredicate.parse(url)!);
|
return super.setThumbnail(imageURLPredicate.parse(url)!);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override setTimestamp(timestamp: number | Date | null = Date.now()): this {
|
public override setTimestamp(timestamp: number | Date | null = Date.now()): this {
|
||||||
|
|||||||
16
yarn.lock
16
yarn.lock
@@ -1758,6 +1758,7 @@ __metadata:
|
|||||||
"@babel/preset-env": ^7.16.11
|
"@babel/preset-env": ^7.16.11
|
||||||
"@babel/preset-typescript": ^7.16.7
|
"@babel/preset-typescript": ^7.16.7
|
||||||
"@discordjs/ts-docgen": ^0.3.4
|
"@discordjs/ts-docgen": ^0.3.4
|
||||||
|
"@sapphire/shapeshift": ^2.0.0
|
||||||
"@sindresorhus/is": ^4.4.0
|
"@sindresorhus/is": ^4.4.0
|
||||||
"@types/jest": ^27.4.0
|
"@types/jest": ^27.4.0
|
||||||
"@types/node": ^16.11.24
|
"@types/node": ^16.11.24
|
||||||
@@ -1777,7 +1778,6 @@ __metadata:
|
|||||||
tsup: ^5.11.13
|
tsup: ^5.11.13
|
||||||
typedoc: ^0.22.11
|
typedoc: ^0.22.11
|
||||||
typescript: ^4.5.5
|
typescript: ^4.5.5
|
||||||
zod: ^3.11.6
|
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
@@ -2317,6 +2317,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@sapphire/shapeshift@npm:^2.0.0":
|
||||||
|
version: 2.0.0
|
||||||
|
resolution: "@sapphire/shapeshift@npm:2.0.0"
|
||||||
|
checksum: e866aa714d70b0c0d607ed9ad831c039b396cca30611691c59a6e43cb369cf23d69404560105101231f56128022b0030a5201c074193da324ad4345c6d06992c
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@sapphire/snowflake@npm:^3.1.0":
|
"@sapphire/snowflake@npm:^3.1.0":
|
||||||
version: 3.1.0
|
version: 3.1.0
|
||||||
resolution: "@sapphire/snowflake@npm:3.1.0"
|
resolution: "@sapphire/snowflake@npm:3.1.0"
|
||||||
@@ -11308,10 +11315,3 @@ dts-critic@latest:
|
|||||||
checksum: f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700
|
checksum: f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"zod@npm:^3.11.6":
|
|
||||||
version: 3.11.6
|
|
||||||
resolution: "zod@npm:3.11.6"
|
|
||||||
checksum: 044ac416450f179a0c88240f27849d2886c777cebade42df10e5f04125b0265cec82d9bd741a7dcb11796b2ea88b32c86be7d36932a4bed6af57002560359db1
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|||||||
Reference in New Issue
Block a user