UNPKG

meocord

Version:

Decorator-based Discord bot framework built on discord.js. Brings NestJS-style controllers, dependency injection, guards, and testing utilities to bot development — with a full CLI and TypeScript-first design.

170 lines (167 loc) 5.93 kB
import CliTable3 from 'cli-table3'; import { findModulePackageDir } from './common.util.js'; import path from 'node:path'; import fs__default from 'node:fs'; import wait from './wait.util.js'; import chalk from 'chalk'; function configureCommandHelp(command) { command.configureHelp({ formatHelp: (cmd, helper)=>{ return formatHelp(cmd, helper, command.options); } }); command.commands.forEach((cmd)=>{ configureCommandHelp(cmd); }); } /** * Formats the help output for a command. * * @param cmd - The command for which to format help. * @param helper - The helper object for formatting. * @param options - The options available for the command. * @returns The formatted help text. */ function formatHelp(cmd, helper, options) { let helpText = `MeoCord Copyright (c) 2025 Ukasyah Rahmatullah Zada — MIT License\n\n`; helpText += `${helper.commandUsage(cmd)}\n\n`; helpText += `${helper.commandDescription(cmd)}\n\n`; if (cmd.registeredArguments.length > 0) { helpText += generateArgumentsTable(cmd.registeredArguments); helpText += '\n\n'; } if (options.length > 0) { helpText += 'Available Options:\n'; helpText += generateOptionsTable(options, helper); helpText += '\n\n'; } if (cmd.commands.length > 0) { helpText += 'Available Commands:\n'; helpText += generateCommandsTable(cmd); helpText += '\n'; } return helpText; } /** * Generates a table of commands with their aliases and descriptions. * * @param cmd - The command for which to generate the table. * @returns The formatted table of commands. */ function generateCommandsTable(cmd) { const table = new CliTable3({ head: [ 'Command', 'Alias', 'Description' ] }); cmd.commands.forEach((cmd)=>{ const alias = cmd.aliases().length > 0 ? cmd.aliases().join(', ') : '—'; const description = cmd.description() || 'No description provided'; table.push([ cmd.name(), alias, description ]); }); return table.toString(); } /** * Generates a table of commands with their aliases and descriptions. * * @param options * @param helper * @returns The formatted table of commands. */ function generateOptionsTable(options, helper) { const table = new CliTable3({ head: [ 'Option', 'Description' ] }); options.forEach((option)=>table.push([ helper.optionTerm(option), helper.optionDescription(option) ])); return table.toString(); } /** * Generates a formatted table of arguments for the specified command. * * This method creates two tables: * 1. A table displaying argument names and their descriptions. * 2. (If applicable) A table showing available choices for arguments with predefined choices. * * @param args - The list of arguments for the command. * @returns A string representation of the formatted tables, including available arguments and their choices. */ function generateArgumentsTable(args) { const table = new CliTable3({ head: [ 'Argument', 'Description' ] }); const choiceTable = new CliTable3({ head: [ 'Choice' ] }); let hasChoices = false; args.forEach((arg)=>{ if (arg.argChoices) { hasChoices = true; arg.argChoices.forEach((choice)=>{ choiceTable.push([ choice ]); }); } table.push([ arg.name(), arg.description || 'No description provided' ]); }); let text = ''; if (hasChoices) { text += 'Available Choices:\n'; text += choiceTable.toString(); text += '\n\n'; } else { text += 'No available choices.\n\n'; } text += 'Available Arguments:\n'; text += table.toString(); return text; } /** * Ensures that the script is being run from the root directory of the project. * Validates the existence of required files, dependencies, and configuration. * If validation fails, it logs an error message and terminates the process. */ async function ensureReady() { const meocordPath = findModulePackageDir('meocord'); const packageJsonPath = path.resolve(process.cwd(), 'package.json'); try { // Ensure the root package.json exists if (!fs__default.existsSync(packageJsonPath)) { throw new Error('package.json not found. This script must be run from the root directory of the project.'); } // Ensure the MeoCord package directory is found if (!meocordPath) { throw new Error('Cannot locate the "MeoCord" package directory.'); } // Read and parse the root package.json const { dependencies } = JSON.parse(fs__default.readFileSync(packageJsonPath, 'utf-8')); // Read and parse the MeoCord package.json const internalPackageJsonPath = path.join(meocordPath, 'package.json'); const { name: internalPackageName } = JSON.parse(fs__default.readFileSync(internalPackageJsonPath, 'utf-8')); // Validate that MeoCord is listed as a dependency in the root package.json if (!dependencies?.[internalPackageName]) { throw new Error('The package.json does not list "MeoCord" as a dependency. Ensure you are in the root directory.'); } } catch (error) { // Log the error and exit the process console.error(chalk.red(error instanceof Error ? error.message : 'An unknown error occurred during validation.')); await wait(100); process.exit(1); } } export { configureCommandHelp, ensureReady, formatHelp, generateArgumentsTable, generateCommandsTable, generateOptionsTable };