Structures_AchievementBuilder.js
'user strict'
const { ErrorCodes } = require('../Errors/ErrorCodes')
const { capitalize } = require('../Utils/Capitalize')
const { AchievementType, AchievementStatus } = require('../Interfaces')
const { isNotPositiveInteger } = require('../Utils/ValidateInteger')
const { InvalidDataArgument, BuilderInvalidNumber, AchievementInvalidProgress, InvalidValue } = require('../Errors/LME')
/** @typedef {import('../../typings').AchievementData} AchievementData */
/** @typedef {import('../../typings').Achievement} Achievement */
/**
* Represents an achievement that can be used to store in the guild or user.
*/
class AchievementBuilder {
/** @type {AchievementData} - Data of the achievement. */
data
/**
* @param {AchievementData} [data] - Data to build the achievement
*/
constructor (data = {}) {
if (typeof data !== 'object') throw new InvalidDataArgument(ErrorCodes.InvalidDataArgument)
this.data = {
status: AchievementStatus.Locked
}
// Call the setter methods to set the data.
for (const [key, value] of Object.entries(data).filter(([keyName, _]) => keyName !== 'status')) this[`set${capitalize(key)}`](value)
}
/**
* Sets the name of the achievement.
* @param {String} name - Name of the achievement
* @returns {AchievementBuilder}
*/
setName (name) {
if (typeof name !== 'string') throw new InvalidValue(ErrorCodes.InvalidValue, 'name', 'a string')
this.data.name = name
return this
}
/**
* Sets the description of the achievement.
* @param {String} description - Description of the achievement
* @returns {AchievementBuilder}
*/
setDescription (description) {
if (typeof description !== 'string') throw new InvalidValue(ErrorCodes.InvalidValue, 'description', 'a string')
this.data.description = description
return this
}
/**
* Sets the thumbnail of the achievement.
* @param {String} thumbnail - Thumbnail of the achievement
* @returns {AchievementBuilder}
*/
setThumbnail (thumbnail) {
if (typeof thumbnail !== 'string') throw new InvalidValue(ErrorCodes.InvalidValue, 'thumbnail', 'a string')
this.data.thumbnail = thumbnail
return this
}
/**
* Sets the reward of the achievement.
* @param {Number} reward - Reward of the achievement
* @returns {AchievementBuilder}
*/
setReward (reward) {
if (isNotPositiveInteger(reward)) throw new BuilderInvalidNumber(ErrorCodes.BuilderInvalidNumber, 'reward')
this.data.reward = reward
return this
}
/**
* Sets the type of the achievement.
* @param {AchievementType} type - Type of the achievement
* @returns {AchievementBuilder}
*/
setType (type) {
if (!Object.values(AchievementType).includes(type)) throw new InvalidValue(ErrorCodes.InvalidValue, 'type', 'a AchievementType')
this.data.type = type
return this
}
/**
* Sets the progress of the achievement.
* @param {Number[]} progress - Progress of the achievement
* @returns {AchievementBuilder}
*/
setProgress (progress) {
if (!progress || !Array.isArray(progress) || progress.length !== 2) throw new AchievementInvalidProgress(ErrorCodes.AchievementInvalidProgress)
if (progress.some(v => typeof v !== 'number' || v < 0 || isNaN(v) || !isFinite(v) || v % 1 !== 0)) throw new AchievementInvalidProgress(ErrorCodes.AchievementNegativeProgress)
if (progress[0] > progress[1]) throw new AchievementInvalidProgress(ErrorCodes.AchievementGraterProgress)
this.data.progress = progress
return this
}
/**
* Returns the JSON representation of the achievement.
* @returns {AchievementData}
*/
toJSON () {
return {
name: this.data.name,
description: this.data.description,
thumbnail: this.data.thumbnail,
type: this.data.type,
reward: this.data.reward,
progress: this.data.progress
}
}
}
module.exports = { AchievementBuilder }