UNPKG

hytescript.js

Version:

A package for programming anything you want with ease.

309 lines (263 loc) 12.2 kB
const { Client, IntentsBitField, ActivityType, Partials } = require("discord.js"); const { compile } = require("../compiler"); const { Database, commandTypes, Functions, replaceLast, getDirFiles, Events, error, Command, HscLog, Data, Time, wait } = require("./utils/utils"); class DiscordClient { /** Initialize a Discord Client in HyteScript.js using Discord.js. * * Example: * ```js * const { DiscordClient } = require('hytescript.js') * * const client = new DiscordClient({ * token: "your bot token", * prefix: '!', * intents: ["GUILDS", "GUILD_MEMBERS", "GUILD_MESSAGES"] * }) * ``` * * Example importing a file with client options: * ```js * const { DiscordClient } = require('hytescript.js') * const config = require('./config.json') * * const client = new DiscordClient(config) * ``` * * @param {{token: string, prefix: string, intents: string[] | number | string, debug?: boolean, respondBots?: boolean, logErrors?: boolean}} options Object with client options. * * */ constructor (options) { /* ++++++++ -:::::::: :::: ++++++++ =:::::::: ::::: ++++++++ +=:::::::: :::: ++++++++ ++-::::::: ::::: ++++++++ ++=::::::: :::: ++++++++ +++-::::::: ::::: ++++++++++++++++++=::::::: :::: +++++++++++++++++++=:::::::::::: ++++++++++++++++++++-:::::::::: ++++++++++++++++++++=::::::::: ++++++++ ++++++-:::::::: ++++++++ ++++++=::::::: ++++++++ +++++++-:::::: ++++++++ =======-::::: ++++++++ ::::::::::::: ++++++++ :::::::::::: ++++++++ :::::::::: */ let {token, intents, prefix, debug = false, respondBots = false, logJSErrors = false} = options; // validating parameters if (typeof token !== 'string') return new error('client', `invalid TOKEN in <HIDEN>`) if (intents === 'all') return new error('client', `"all" intents is deprecated. Use intents array instead`) if (!Array.isArray(intents)) return new error('client', `invalid INTENTS in "${intents}"`) if (typeof prefix !== 'string' && !Array.isArray(prefix)) return new error('client', `invalid PREFIX in "${prefix}"`) // validating prefix const wrong = prefix?.find?.(x => typeof x !== 'string') if (typeof prefix === 'string') prefix = [prefix] else if (wrong != undefined) return new error('client', `prefixes must be string. Received ${typeof wrong} in "${wrong}"`) // validating intents const validIntents = Object.keys(IntentsBitField.Flags) const validatedIntents = [] for (const intent of intents) { let foundIntent = validIntents.find(x => x.toLowerCase() === (typeof intent == 'string' ? intent.toLowerCase().replaceAll('_', '') : JSON.stringify(intent))) if (!foundIntent || !['string', 'number'].includes(typeof intent)) return new error('client', `invalid intent in "${intent}"`) validatedIntents.push(isNaN(foundIntent) ? IntentsBitField.Flags[foundIntent] : Number(foundIntent)) } const client = new Client({ intents: validatedIntents, partials: Object.values(Partials) }); this.data = { clientOptions: { token, intents, respondBots, debug, logJSErrors, prefix: prefix.map(x => compile(x)) }, client, status: [], databases: {}, internalDatabase: new Database('internal', 'internal'), commandManager: commandTypes, functions: new Functions(), events: new Events(), commands: [], invite: 'https://discord.gg/bdUENGdN88', version: require("../../../package.json").version, error, data: new Data({ message: { content: '', embeds: [], components: [], files: [], reply: undefined, allowedMentions: { parse: ['users', 'roles', 'everyone'], repliedUser: true, }, tts: false, reset() { this.content = '' this.embeds = [] this.components = [] this.files = [] this.reply = undefined this.allowedMentions = { parse: ['users', 'roles', 'everyone'], repliedUser: true } this.tts = false } }, logJSErrors }) } this.data.events.get('ready')(this.data) client.login(token); setTimeout(() => { if (!client.isReady()) { if (process.env.REPLIT_CLUSTER != undefined) { const childProcess = require("child_process") HscLog.warn(`Repl.it is having some problems to turn on your bot. Please, wait until the problem get solved for you. Press the "Run" button when it pop up.`) wait(5000).then(() => { childProcess.execSync('kill 1') }) } else { HscLog.warn(`client took 15 seconds to initialize.\nIf you're using Repl.it to host your bot, turn off your bot and execute \x1b[30;1mkill 1\x1b[0m in your shell. If it don't solve your problem, try again. If.\nIf you're using any other hosting service and that's happening, please, come to our support: \x1b[36;1m${this.data.invite}\x1b[0m`) } } }, 15000); }; /** * Adds commands to the client. * * Example: * ```js * const { DiscordClient } = require('hytescript.js') * * const client = new DiscordClient({ * token: "your bot token", * prefix: '!', * intents: ["GUILDS", "GUILD_MEMBERS", "GUILD_MESSAGES"] * }) * * client.addCommands({ * name: 'hello', * code: `Hey, what's up?` * }) * * client.addEvents('messageCreate') // messageCreate event is needed to run default commands * ``` * Running the command added: `!hello` * * Bot will respond: "Hey, what's up?" * * * * @param {...{name?: string, code: string, aliases?: string[], type?: string, executeOnDM?: boolean, ignorePrefix?: boolean, enableComments?: boolean}} commands a command object */ addCommands(...commands) { for (const command of commands) { command.path = '<main file>' this.data.commands.push(new Command(command, this.data.commandManager)) } return this /*console.log('Loading main file commands...') let load = 0 let plusAmount = (100 / commands.length).toFixed(2) for (const command of commands) { command.path = 'index.js' let parseData = utils.parseCommand(this.data, command) for (let row of parseData.table.__rows) { this.data.table.addRow(...row) } load = Math.round(load + plusAmount) console.log(load > 100 ? `\x1b[35m100%\x1b[0m` : `\x1b[35m${load}%\x1b[0m`) }*/ } /** * * @param {string} path the folder path */ readFolder(path) { let files = getDirFiles(path) for (let file of files) { let commands = [] try { let commandReq = require(file.path) if (typeof commandReq == 'object') { if (Array.isArray(commandReq)) commands.push(...commandReq) else commands.push(commandReq) for (const command of commands) { command.path = file.path this.data.commands.push(new Command(command, this.data.commandManager)) } } else { HscLog.warn(`folderReader: command path "${file.path}" couldn't be loaded.`) } } catch (e) { if (this.data.clientOptions.logJSErrors) console.error(e) HscLog.warn(`folderReader: command path "${file.path}" couldn't be loaded: ${e.message}`) } }; return this }; addEvents(...events) { const wrongEvent = events.find(x => typeof x !== 'string') if (wrongEvent) return new error('client', `client#addEvents: events must be string. Received ${typeof wrongEvent} in "${wrongEvent}"`) for (const event of events) { if (event.toLowerCase() === 'ready') HscLog.warn(`'ready' event already have been preadded.`) else { let runEvent = this.data.events.get(event.toLowerCase()); if (!runEvent) return new error('client', `invalid event in "${event}"`) runEvent(this.data); } } return this }; addStatus(...optionsArray) { let index = 0 for (const options of optionsArray) { let {text, type = 'PLAYING', status = 'online', time = 10000} = options; if (typeof time != "number" && typeof time === 'string') { if (!isNaN(time)) time = Number(time) else { const parsedTime = Time.parseTime(time) if (parsedTime.error) return new error('client', `invalid time in "${time}" at status ${d.status.length + 1}.`) time = parsedTime.ms } } if (time < 0) return new error('client', `time must be above to 0 at status ${d.status.length + 1}.`) let types = { PLAYING: ActivityType.Playing, LISTENING: ActivityType.Listening, WATCHING: ActivityType.Watching, STREAMING: ActivityType.Streaming, COMPETING: ActivityType.Competing, CUSTOM: ActivityType.Custom, } if (types[type.toUpperCase()] == undefined) return new error('client', `invalid activity type at status ${d.status.length + 1}.`) type = types[type.toUpperCase()] this.data.status.push({ text: compile(text), type, status, time }); } return this }; addDatabase(name, entries, options = {}) { if (typeof name !== 'string') throw new TypeError(`name must be a string.`) if (typeof entries !== "object" || !JSON.stringify(entries).startsWith("{")) throw new TypeError(`entries must be an object.`) if (this.data.databases.hasOwnProperty(name)) throw new TypeError(`database with name "${name}" already exists.`) const newDb = new Database(name, "databases", entries, options) this.data.databases[name] = newDb; return this } addFunctions(...functions) { for (const func of functions) { const {name, description, usage, parameters, aliases, dontParse = [], dontUnescape = [], code: run} = func this.data.functions.set(name.toLowerCase(), { description, usage, parameters, aliases, dontParse, dontUnescape, run }) } return this } }; module.exports = DiscordClient;