mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-18 12:33:30 +01:00
refactor: improve structure validation with zod (#10103)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
@@ -19,6 +19,7 @@
|
|||||||
"eslint": "^8.53.0",
|
"eslint": "^8.53.0",
|
||||||
"eslint-config-neon": "^0.1.57",
|
"eslint-config-neon": "^0.1.57",
|
||||||
"eslint-formatter-pretty": "^5.0.0",
|
"eslint-formatter-pretty": "^5.0.0",
|
||||||
"prettier": "^3.1.0"
|
"prettier": "^3.1.0",
|
||||||
|
"zod": "^3.22.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
"eslint-config-neon": "^0.1.57",
|
"eslint-config-neon": "^0.1.57",
|
||||||
"eslint-formatter-pretty": "^5.0.0",
|
"eslint-formatter-pretty": "^5.0.0",
|
||||||
"prettier": "^3.1.0",
|
"prettier": "^3.1.0",
|
||||||
"typescript": "^5.2.2"
|
"typescript": "^5.2.2",
|
||||||
|
"zod": "^3.22.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { RESTPostAPIApplicationCommandsJSONBody, CommandInteraction } from 'npm:discord.js@^14.14.1';
|
import type { RESTPostAPIApplicationCommandsJSONBody, CommandInteraction } from 'npm:discord.js@^14.14.1';
|
||||||
|
import { z } from 'npm:zod@^3.22.4';
|
||||||
import type { StructurePredicate } from '../util/loaders.ts';
|
import type { StructurePredicate } from '../util/loaders.ts';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,11 +18,16 @@ export type Command = {
|
|||||||
execute(interaction: CommandInteraction): Promise<void> | void;
|
execute(interaction: CommandInteraction): Promise<void> | void;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Defines the predicate to check if an object is a valid Command type
|
/**
|
||||||
|
* Defines the schema for a command
|
||||||
|
*/
|
||||||
|
export const schema = z.object({
|
||||||
|
data: z.record(z.any()),
|
||||||
|
execute: z.function(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the predicate to check if an object is a valid Command type.
|
||||||
|
*/
|
||||||
export const predicate: StructurePredicate<Command> = (structure): structure is Command =>
|
export const predicate: StructurePredicate<Command> = (structure): structure is Command =>
|
||||||
Boolean(structure) &&
|
schema.safeParse(structure).success;
|
||||||
typeof structure === 'object' &&
|
|
||||||
'data' in structure! &&
|
|
||||||
'execute' in structure &&
|
|
||||||
typeof structure.data === 'object' &&
|
|
||||||
typeof structure.execute === 'function';
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { ClientEvents } from 'npm:discord.js@^14.14.1';
|
import type { ClientEvents } from 'npm:discord.js@^14.14.1';
|
||||||
|
import { z } from 'npm:zod@^3.22.4';
|
||||||
import type { StructurePredicate } from '../util/loaders.ts';
|
import type { StructurePredicate } from '../util/loaders.ts';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,11 +24,17 @@ export type Event<T extends keyof ClientEvents = keyof ClientEvents> = {
|
|||||||
once?: boolean;
|
once?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Defines the predicate to check if an object is a valid Event type.
|
/**
|
||||||
export const predicate: StructurePredicate<Event> = (structure): structure is Event =>
|
* Defines the schema for an event.
|
||||||
Boolean(structure) &&
|
*/
|
||||||
typeof structure === 'object' &&
|
export const schema = z.object({
|
||||||
'name' in structure! &&
|
name: z.string(),
|
||||||
'execute' in structure &&
|
once: z.boolean().optional().default(false),
|
||||||
typeof structure.name === 'string' &&
|
execute: z.function(),
|
||||||
typeof structure.execute === 'function';
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the predicate to check if an object is a valid Event type.
|
||||||
|
*/
|
||||||
|
export const predicate: StructurePredicate<Event> = (structure: unknown): structure is Event =>
|
||||||
|
schema.safeParse(structure).success;
|
||||||
|
|||||||
@@ -58,7 +58,9 @@ export async function loadStructures<T>(
|
|||||||
const structure = (await import(`${dir}/${file}`)).default;
|
const structure = (await import(`${dir}/${file}`)).default;
|
||||||
|
|
||||||
// If the structure is a valid structure, add it
|
// If the structure is a valid structure, add it
|
||||||
if (predicate(structure)) structures.push(structure);
|
if (predicate(structure)) {
|
||||||
|
structures.push(structure);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return structures;
|
return structures;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
"eslint": "^8.53.0",
|
"eslint": "^8.53.0",
|
||||||
"eslint-config-neon": "^0.1.57",
|
"eslint-config-neon": "^0.1.57",
|
||||||
"eslint-formatter-pretty": "^5.0.0",
|
"eslint-formatter-pretty": "^5.0.0",
|
||||||
"prettier": "^3.1.0"
|
"prettier": "^3.1.0",
|
||||||
|
"zod": "^3.22.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the structure of a command.
|
* Defines the structure of a command.
|
||||||
*
|
*
|
||||||
@@ -6,16 +8,18 @@
|
|||||||
* @property {(interaction: import('discord.js').CommandInteraction) => Promise<void> | void} execute The function to execute when the command is called
|
* @property {(interaction: import('discord.js').CommandInteraction) => Promise<void> | void} execute The function to execute when the command is called
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the schema for a command
|
||||||
|
*/
|
||||||
|
export const schema = z.object({
|
||||||
|
data: z.record(z.any()),
|
||||||
|
execute: z.function(),
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the predicate to check if an object is a valid Command type.
|
* Defines the predicate to check if an object is a valid Command type.
|
||||||
*
|
*
|
||||||
* @type {import('../util/loaders.js').StructurePredicate<Command>}
|
* @type {import('../util/loaders.js').StructurePredicate<Command>}
|
||||||
* @returns {structure is Command}
|
* @returns {structure is Command}
|
||||||
*/
|
*/
|
||||||
export const predicate = (structure) =>
|
export const predicate = (structure) => schema.safeParse(structure).success;
|
||||||
Boolean(structure) &&
|
|
||||||
typeof structure === 'object' &&
|
|
||||||
'data' in structure &&
|
|
||||||
'execute' in structure &&
|
|
||||||
typeof structure.data === 'object' &&
|
|
||||||
typeof structure.execute === 'function';
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the structure of an event.
|
* Defines the structure of an event.
|
||||||
*
|
*
|
||||||
@@ -8,16 +10,20 @@
|
|||||||
* @property {boolean} [once] Whether or not the event should only be listened to once
|
* @property {boolean} [once] Whether or not the event should only be listened to once
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the schema for an event.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export const schema = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
once: z.boolean().optional().default(false),
|
||||||
|
execute: z.function(),
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the predicate to check if an object is a valid Event type.
|
* Defines the predicate to check if an object is a valid Event type.
|
||||||
*
|
*
|
||||||
* @type {import('../util/loaders').StructurePredicate<Event>}
|
* @type {import('../util/loaders').StructurePredicate<Event>}
|
||||||
* @returns {structure is Event}
|
* @returns {structure is Event}
|
||||||
*/
|
*/
|
||||||
export const predicate = (structure) =>
|
export const predicate = (structure) => schema.safeParse(structure).success;
|
||||||
Boolean(structure) &&
|
|
||||||
typeof structure === 'object' &&
|
|
||||||
'name' in structure &&
|
|
||||||
'execute' in structure &&
|
|
||||||
typeof structure.name === 'string' &&
|
|
||||||
typeof structure.execute === 'function';
|
|
||||||
|
|||||||
@@ -55,7 +55,9 @@ export async function loadStructures(dir, predicate, recursive = true) {
|
|||||||
const structure = (await import(`${dir}/${file}`)).default;
|
const structure = (await import(`${dir}/${file}`)).default;
|
||||||
|
|
||||||
// If the structure is a valid structure, add it
|
// If the structure is a valid structure, add it
|
||||||
if (predicate(structure)) structures.push(structure);
|
if (predicate(structure)) {
|
||||||
|
structures.push(structure);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return structures;
|
return structures;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
"eslint-config-neon": "^0.1.57",
|
"eslint-config-neon": "^0.1.57",
|
||||||
"eslint-formatter-pretty": "^5.0.0",
|
"eslint-formatter-pretty": "^5.0.0",
|
||||||
"prettier": "^3.1.0",
|
"prettier": "^3.1.0",
|
||||||
"typescript": "^5.2.2"
|
"typescript": "^5.2.2",
|
||||||
|
"zod": "^3.22.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { RESTPostAPIApplicationCommandsJSONBody, CommandInteraction } from 'discord.js';
|
import type { RESTPostAPIApplicationCommandsJSONBody, CommandInteraction } from 'discord.js';
|
||||||
|
import { z } from 'zod';
|
||||||
import type { StructurePredicate } from '../util/loaders.[REPLACE_IMPORT_EXT]';
|
import type { StructurePredicate } from '../util/loaders.[REPLACE_IMPORT_EXT]';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,11 +18,16 @@ export type Command = {
|
|||||||
execute(interaction: CommandInteraction): Promise<void> | void;
|
execute(interaction: CommandInteraction): Promise<void> | void;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Defines the predicate to check if an object is a valid Command type
|
/**
|
||||||
export const predicate: StructurePredicate<Command> = (structure): structure is Command =>
|
* Defines the schema for a command
|
||||||
Boolean(structure) &&
|
*/
|
||||||
typeof structure === 'object' &&
|
export const schema = z.object({
|
||||||
'data' in structure! &&
|
data: z.record(z.any()),
|
||||||
'execute' in structure &&
|
execute: z.function(),
|
||||||
typeof structure.data === 'object' &&
|
});
|
||||||
typeof structure.execute === 'function';
|
|
||||||
|
/**
|
||||||
|
* Defines the predicate to check if an object is a valid Command type.
|
||||||
|
*/
|
||||||
|
export const predicate: StructurePredicate<Command> = (structure: unknown): structure is Command =>
|
||||||
|
schema.safeParse(structure).success;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { ClientEvents } from 'discord.js';
|
import type { ClientEvents } from 'discord.js';
|
||||||
|
import { z } from 'zod';
|
||||||
import type { StructurePredicate } from '../util/loaders.[REPLACE_IMPORT_EXT]';
|
import type { StructurePredicate } from '../util/loaders.[REPLACE_IMPORT_EXT]';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,11 +24,17 @@ export type Event<T extends keyof ClientEvents = keyof ClientEvents> = {
|
|||||||
once?: boolean;
|
once?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Defines the predicate to check if an object is a valid Event type.
|
/**
|
||||||
export const predicate: StructurePredicate<Event> = (structure): structure is Event =>
|
* Defines the schema for an event.
|
||||||
Boolean(structure) &&
|
*/
|
||||||
typeof structure === 'object' &&
|
export const schema = z.object({
|
||||||
'name' in structure! &&
|
name: z.string(),
|
||||||
'execute' in structure &&
|
once: z.boolean().optional().default(false),
|
||||||
typeof structure.name === 'string' &&
|
execute: z.function(),
|
||||||
typeof structure.execute === 'function';
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the predicate to check if an object is a valid Event type.
|
||||||
|
*/
|
||||||
|
export const predicate: StructurePredicate<Event> = (structure: unknown): structure is Event =>
|
||||||
|
schema.safeParse(structure).success;
|
||||||
|
|||||||
Reference in New Issue
Block a user