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
JavaScript
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 };