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.

115 lines (112 loc) 6.35 kB
import path from 'path'; import { ControllerType } from '../../enum/controller.enum.js'; import { validateAndFormatName, populateTemplate, createDirectoryIfNotExists, generateFile, toClassName } from '../../util/generator-cli.util.js'; import { fileURLToPath } from 'url'; const __filename$1 = fileURLToPath(import.meta.url); const __dirname$1 = path.dirname(__filename$1); class ControllerGeneratorHelper { /** * Generates a new controller file and an associated structure based on the provided arguments and controller type. * @param args - The arguments for generating the controller, including the optional controller name. * @param type - The type of the controller to generate, defined in the `ControllerType` enum. * @throws Will throw an error if the controller name is invalid or if the controller type is unsupported. */ generateController(args, type) { const { parts, kebabCaseName, className } = validateAndFormatName(args.controllerName); const controllerDir = path.join(process.cwd(), 'src', 'controllers', type, ...parts); const template = this.buildControllerTemplate(className, type); this.generateControllerStructure(controllerDir, kebabCaseName, className, type, template); } /** * Builds the controller template content by populating a template with variables. * @param className - The name of the controller class. * @param type - The type of the controller, defined in the `ControllerType` enum. * @returns The populated template string for the controller. * @throws Will throw an error if the controller type is unsupported. */ buildControllerTemplate(className, type) { const templateConfig = this.getTemplateConfig(type, className); if (!templateConfig) { throw new Error(`Unsupported controller type: ${type}`); } return populateTemplate(templateConfig.template, templateConfig.variables); } /** * Retrieves the template configuration for a specific controller type and class name. * @param type - The type of the controller, defined in the `ControllerType` enum. * @param className - The name of the controller class. * @returns An object containing the template path and variables, or `undefined` if not found. */ getTemplateConfig(type, className) { const baseDir = path.resolve(__dirname$1, '..', 'builder-template', 'controller'); const templates = { [ControllerType.BUTTON]: 'button.controller.template', [ControllerType.MODAL_SUBMIT]: 'modal-submit.controller.template', [ControllerType.SELECT_MENU]: 'select-menu.controller.template', [ControllerType.REACTION]: 'reaction.controller.template', [ControllerType.MESSAGE]: 'message.controller.template', [ControllerType.CONTEXT_MENU]: 'context-menu.controller.template', [ControllerType.SLASH]: 'slash.controller.template' }; const template = templates[type] ? path.resolve(baseDir, templates[type]) : undefined; return template ? { template, variables: { className } } : undefined; } /** * Generates the controller file and its associated structure (e.g., builder files, directories). * @param controllerDir - The absolute path to the controller directory. * @param kebabCaseName - The kebab-case name of the controller file. * @param className - The name of the controller class. * @param type - The type of the controller, defined in the `ControllerType` enum. * @param controllerTemplate - The populated template string for the controller file. */ generateControllerStructure(controllerDir, kebabCaseName, className, type, controllerTemplate) { this.generateBuilderFile(className, type, controllerDir); createDirectoryIfNotExists(controllerDir); const controllerFilePath = path.join(controllerDir, `${kebabCaseName}.${type}.controller.ts`); generateFile(controllerFilePath, controllerTemplate); const typeClassName = toClassName(type.replace(/-/g, ' ')); const specTemplatePath = path.resolve(__dirname$1, '..', 'builder-template', 'controller', 'controller.spec.template'); const specContent = populateTemplate(specTemplatePath, { className, kebabCaseName, type, typeClassName }); generateFile(path.join(controllerDir, `${kebabCaseName}.${type}.controller.spec.ts`), specContent); } /** * Generates a builder file for the specified controller type and stores it in the controller directory. * @param className - The name of the controller class. * @param type - The type of the controller, defined in the `ControllerType` enum. * @param controllerDir - The absolute path to the controller directory. */ generateBuilderFile(className, type, controllerDir) { const builderConfig = this.getBuilderConfig(type, className); if (!builderConfig) return; const builderTemplate = populateTemplate(builderConfig.template, builderConfig.variables); const buildersDir = path.join(controllerDir, 'builders'); createDirectoryIfNotExists(buildersDir); const builderFilePath = path.join(buildersDir, 'sample.builder.ts'); generateFile(builderFilePath, builderTemplate); } /** * Retrieves the configuration for generating a builder file based on the controller type and class name. * @param type - The type of the controller, defined in the `ControllerType` enum. * @param className - The name of the controller class. * @returns An object containing the builder template path and variables, or `undefined` if not found. */ getBuilderConfig(type, className) { const baseDir = path.resolve(__dirname$1, '..', 'builder-template', 'builder'); const templates = { [ControllerType.CONTEXT_MENU]: 'context-menu.builder.template', [ControllerType.SLASH]: 'slash.builder.template' }; const template = templates[type] ? path.resolve(baseDir, templates[type]) : undefined; return template ? { template, variables: { className } } : undefined; } } export { ControllerGeneratorHelper };