discord-starboard-plus
Version:
Discord Starboard Plus: A clean, maintainable starboard system for Discord.js bots. Features per-guild configuration, TypeScript support. Highlight your community's favorite messages with customizable starboards.
143 lines • 5.62 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfigValidator = void 0;
/**
* Default configuration values
*/
const DEFAULT_OPTIONS = {
starEmoji: '\u2b50',
requiredReactions: 1,
ignoreBots: true,
ignoreSelf: false,
ignoredChannels: [],
ignoreGuilds: [],
updateOnReaction: true,
logActions: true,
embedColor: 0xFFAC33,
maxAttachments: 4,
allowNSFW: false,
jumpToMessage: true,
showMessageDate: true,
maxSearchDepth: 500,
useComponentsV2: false
};
/**
* Configuration validation and normalization.
* Centralizes all configuration logic following SRP.
*/
class ConfigValidator {
/**
* Validate configuration options.
* Throws an error if validation fails.
*/
static validate(options) {
const errors = [];
// Required fields
if (!options.starboardChannelID) {
errors.push('starboardChannelID is required');
}
else if (!ConfigValidator.isValidSnowflake(options.starboardChannelID)) {
errors.push('starboardChannelID must be a valid Discord Snowflake');
}
// Numeric validations
if (options.requiredReactions !== undefined) {
if (!Number.isInteger(options.requiredReactions) || options.requiredReactions < 1) {
errors.push('requiredReactions must be a positive integer');
}
}
if (options.maxAttachments !== undefined) {
if (!Number.isInteger(options.maxAttachments) || options.maxAttachments < 0) {
errors.push('maxAttachments must be a non-negative integer');
}
}
if (options.maxSearchDepth !== undefined) {
if (!Number.isInteger(options.maxSearchDepth) || options.maxSearchDepth < 100) {
errors.push('maxSearchDepth must be an integer >= 100');
}
}
// Array validations
if (options.ignoredChannels !== undefined) {
if (!Array.isArray(options.ignoredChannels)) {
errors.push('ignoredChannels must be an array');
}
else if (!options.ignoredChannels.every(ConfigValidator.isValidSnowflake)) {
errors.push('ignoredChannels must contain valid Discord Snowflakes');
}
}
if (options.ignoreGuilds !== undefined) {
if (!Array.isArray(options.ignoreGuilds)) {
errors.push('ignoreGuilds must be an array');
}
else if (!options.ignoreGuilds.every(ConfigValidator.isValidSnowflake)) {
errors.push('ignoreGuilds must contain valid Discord Snowflakes');
}
}
// Emoji validation
if (options.starEmoji !== undefined) {
if (typeof options.starEmoji !== 'string' || options.starEmoji.length === 0) {
errors.push('starEmoji must be a non-empty string');
}
}
if (errors.length > 0) {
throw new Error(`Configuration validation failed:\n- ${errors.join('\n- ')}`);
}
}
/**
* Normalize configuration options by applying defaults.
* Returns a complete StarboardOptions object.
*/
static normalize(options) {
return {
starEmoji: options.starEmoji ?? DEFAULT_OPTIONS.starEmoji,
starboardChannelID: options.starboardChannelID,
requiredReactions: Math.max(1, options.requiredReactions ?? DEFAULT_OPTIONS.requiredReactions),
ignoreBots: options.ignoreBots ?? DEFAULT_OPTIONS.ignoreBots,
ignoreSelf: options.ignoreSelf ?? DEFAULT_OPTIONS.ignoreSelf,
ignoredChannels: [...(options.ignoredChannels ?? DEFAULT_OPTIONS.ignoredChannels)],
ignoreGuilds: [...(options.ignoreGuilds ?? DEFAULT_OPTIONS.ignoreGuilds)],
updateOnReaction: options.updateOnReaction ?? DEFAULT_OPTIONS.updateOnReaction,
logActions: options.logActions ?? DEFAULT_OPTIONS.logActions,
embedColor: options.embedColor ?? DEFAULT_OPTIONS.embedColor,
maxAttachments: Math.max(0, options.maxAttachments ?? DEFAULT_OPTIONS.maxAttachments),
allowNSFW: options.allowNSFW ?? DEFAULT_OPTIONS.allowNSFW,
jumpToMessage: options.jumpToMessage ?? DEFAULT_OPTIONS.jumpToMessage,
showMessageDate: options.showMessageDate ?? DEFAULT_OPTIONS.showMessageDate,
maxSearchDepth: Math.max(100, options.maxSearchDepth ?? DEFAULT_OPTIONS.maxSearchDepth),
useComponentsV2: options.useComponentsV2 ?? DEFAULT_OPTIONS.useComponentsV2
};
}
/**
* Validate and normalize in one step.
*/
static validateAndNormalize(options) {
ConfigValidator.validate(options);
return ConfigValidator.normalize(options);
}
/**
* Merge partial options with existing options.
*/
static merge(existing, partial) {
const merged = {
...existing,
...partial
};
return ConfigValidator.validateAndNormalize(merged);
}
/**
* Check if a string is a valid Discord Snowflake.
*/
static isValidSnowflake(value) {
if (typeof value !== 'string')
return false;
// Snowflakes are numeric strings between 17-20 digits
return /^\d{17,20}$/.test(value);
}
/**
* Get default options (without starboardChannelID)
*/
static getDefaults() {
return { ...DEFAULT_OPTIONS };
}
}
exports.ConfigValidator = ConfigValidator;
//# sourceMappingURL=ConfigValidator.js.map