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