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.

108 lines (105 loc) 4.46 kB
import fs from 'fs'; import path from 'path'; import { exec } from 'child_process'; import { Logger } from '../common/logger.js'; import '../common/theme.js'; import { kebabCase, startCase, camelCase } from 'lodash-es'; import { fileURLToPath } from 'url'; const __filename$1 = fileURLToPath(import.meta.url); const __dirname$1 = path.dirname(__filename$1); const logger = new Logger('MeoCord'); /** * Converts a given name to a properly formatted class name. * @param originalName - The original name to be converted to a class name. * @returns The formatted class name. * @throws Will exit the process if the generated class name is invalid. */ function toClassName(originalName) { const className = startCase(camelCase(originalName)).replace(/\s/g, ''); const classNameRegex = /^[A-Z][A-Za-z0-9]*$/; if (!classNameRegex.test(className)) { logger.error(`Invalid class name "${originalName}". Must start with a letter and contain alphanumeric characters.`); process.exit(1); } return className; } /** * Validates and formats a given name, splitting it into parts, * converting it to kebab-case, and generating a class name. * @param originalName - The name to validate and format. It can include slashes for nested paths. * @returns An object containing the name parts, kebab-case name, and class name. * @throws Will exit the process if the name is undefined, invalid, * or the generated class name is invalid. */ function validateAndFormatName(originalName) { if (!originalName) { logger.error('Guard name is required.'); process.exit(1); } const parts = originalName.split('/'); const fileName = parts.pop(); if (!fileName) { logger.error('Invalid guard name.'); process.exit(1); } const kebabCaseName = kebabCase(fileName); const className = toClassName(fileName); return { parts, kebabCaseName, className }; } /** * Ensures that a given directory exists. Creates the directory and any necessary parent directories if they do not exist. * @param directory - The absolute path of the directory to create. */ function createDirectoryIfNotExists(directory) { if (!fs.existsSync(directory)) { fs.mkdirSync(directory, { recursive: true }); } } /** * Writes the provided content to a file and runs ESLint on the file for formatting. * @param filePath - The absolute path of the file to create or overwrite. * @param content - The content to write to the file. * @throws Logs an error if the file creation or ESLint command fails. */ function generateFile(filePath, content) { try { fs.writeFileSync(filePath, content); logger.log(`Guard file created at: ${path.relative(process.cwd(), filePath)}`); exec(`npx eslint --fix ${filePath}`); } catch (error) { logger.error(`Failed to create guard file at ${filePath}`, error); } } /** * Builds and returns a template string for a given class name using a specific template file. * @param className - The name of the class to insert into the template. * @param templateFileName - The name of the template file to use. * @returns The populated template string. * @throws Will throw an error if the template file cannot be read. */ function buildTemplate(className, templateFileName, extra = {}) { const filePath = path.resolve(__dirname$1, '..', 'bin', 'builder-template', templateFileName); let template = fs.readFileSync(filePath, 'utf-8'); for (const [key, value] of Object.entries({ className, ...extra })){ template = template.replaceAll(`{{${key}}}`, value); } return template; } /** * Populates a template file with the provided variables by replacing placeholders in the template. * @param filePath - The path to the template file. * @param variables - An object containing variable names and their replacement values. * @returns The populated template string. * @throws Will throw an error if the template file cannot be read. */ function populateTemplate(filePath, variables) { let template = fs.readFileSync(filePath, 'utf-8'); for (const [key, value] of Object.entries(variables)){ template = template.replaceAll(`{{${key}}}`, value); } return template; } export { buildTemplate, createDirectoryIfNotExists, generateFile, populateTemplate, toClassName, validateAndFormatName };