UNPKG

dscaffold

Version:

A TypeScript framework for scaffolding modular Discord bot projects with dynamic command and event loading

813 lines (711 loc) 28.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ProjectGenerator = void 0; const path_1 = __importDefault(require("path")); const utils_1 = require("../utils"); const TemplateRenderer_1 = require("./TemplateRenderer"); class ProjectGenerator { constructor(config) { this.config = config; this.templateRenderer = new TemplateRenderer_1.TemplateRenderer(); } async generate(targetPath) { await (0, utils_1.ensureDir)(targetPath); // Generate package.json await this.generatePackageJson(targetPath); // Generate TypeScript/JavaScript config files if (this.config.language === 'typescript') { await this.generateTsConfig(targetPath); } // Generate main bot file await this.generateMainFile(targetPath); // Generate basic structure await this.generateProjectStructure(targetPath); // Generate configuration files await this.generateConfigFiles(targetPath); // Generate example files await this.generateExampleFiles(targetPath); // Generate additional files based on features if (this.config.features.eslint) { await this.generateEslintConfig(targetPath); } if (this.config.features.prettier) { await this.generatePrettierConfig(targetPath); } if (this.config.features.docker) { await this.generateDockerFiles(targetPath); } // Generate README await this.generateReadme(targetPath); } async generatePackageJson(targetPath) { const isTs = this.config.language === 'typescript'; const content = this.getPackageJsonContent(isTs); await (0, utils_1.writeFile)(path_1.default.join(targetPath, 'package.json'), content); } getPackageJsonContent(isTypeScript) { const packageJson = { name: this.config.name, version: "1.0.0", description: "A Discord bot built with Discord.js", main: isTypeScript ? "dist/index.js" : "src/index.js", scripts: { ...(isTypeScript ? { build: "tsc", start: "node dist/index.js", dev: "ts-node-dev --respawn --transpile-only src/index.ts", watch: "tsc --watch" } : { start: "node src/index.js", dev: "nodemon src/index.js" }), ...(this.config.features.eslint ? { lint: `eslint ${isTypeScript ? 'src/**/*.ts' : 'src/**/*.js'}`, "lint:fix": `eslint ${isTypeScript ? 'src/**/*.ts' : 'src/**/*.js'} --fix` } : {}), ...(this.config.features.prettier ? { format: `prettier --write ${isTypeScript ? 'src/**/*.ts' : 'src/**/*.js'}` } : {}), test: 'echo "Error: no test specified" && exit 1' }, dependencies: { "discord.js": "^14.14.1", "dotenv": "^16.4.5", "dscaffold": "^1.0.0", ...(this.config.features.database ? { mongoose: "^8.1.1" } : {}), ...(this.config.features.logging ? { winston: "^3.11.0" } : {}) }, devDependencies: { ...(isTypeScript ? { "@types/node": "^20.11.24", "ts-node": "^10.9.2", "ts-node-dev": "^2.0.0", typescript: "^5.3.3" } : { nodemon: "^3.0.3" }), ...(this.config.features.eslint ? { eslint: "^8.56.0", ...(isTypeScript ? { "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0" } : {}) } : {}), ...(this.config.features.prettier ? { prettier: "^3.2.5", ...(this.config.features.eslint ? { "eslint-config-prettier": "^9.1.0" } : {}) } : {}) }, keywords: ["discord", "bot", "discord.js"], author: "", license: "MIT" }; return JSON.stringify(packageJson, null, 2); } async generateTsConfig(targetPath) { const template = this.getTsConfigTemplate(); const content = this.templateRenderer.render(template, this.config); await (0, utils_1.writeFile)(path_1.default.join(targetPath, 'tsconfig.json'), content); } async generateMainFile(targetPath) { const isTs = this.config.language === 'typescript'; const extension = isTs ? 'ts' : 'js'; const content = this.getMainFileContent(isTs); await (0, utils_1.writeFile)(path_1.default.join(targetPath, `src/index.${extension}`), content); } getMainFileContent(isTypeScript) { const intentsArray = this.config.botSettings.intents.map(intent => `GatewayIntentBits.${intent}`).join(', '); if (isTypeScript) { return `import { Client, GatewayIntentBits } from 'discord.js'; import dscaffold from 'dscaffold'; import dotenv from 'dotenv'; import path from 'path'; ${this.config.features.logging ? "import { logger } from './utils/logger';" : ''} ${this.config.features.database ? "import { connectDB } from './utils/database';" : ''} dotenv.config(); const client = new Client({ intents: [${intentsArray}], }); // Initialize dscaffold and load commands/events async function initialize() { try { // Load commands from the commands directory (supports nested folders) await dscaffold.loadCommands(client, path.join(__dirname, 'commands')); // Load events from the events directory await dscaffold.loadEvents(client, path.join(__dirname, 'events')); ${this.config.features.database ? ' // Connect to database\n await connectDB();' : ''} // Login to Discord await client.login(process.env.DISCORD_TOKEN); } catch (error) { console.error('❌ Failed to initialize bot:', error); process.exit(1); } } // Handle command interactions client.on('messageCreate', async (message) => { if (message.author.bot) return; const prefix = process.env.PREFIX || '${this.config.botSettings.prefix}'; if (!message.content.startsWith(prefix)) return; const args = message.content.slice(prefix.length).trim().split(/ +/); const commandName = args.shift()?.toLowerCase(); if (!commandName) return; const command = dscaffold.getCommand(commandName); if (!command) return; try { await command.execute(message, args); } catch (error) { console.error('❌ Error executing command:', error); message.reply('There was an error executing that command!'); } }); // Handle slash command interactions client.on('interactionCreate', async (interaction) => { if (!interaction.isChatInputCommand()) return; const command = dscaffold.getCommand(interaction.commandName); if (!command) return; try { await command.execute(interaction); } catch (error) { console.error('❌ Error executing slash command:', error); await interaction.reply({ content: 'There was an error executing that command!', ephemeral: true }); } }); // Start the bot initialize();`; } else { return `const { Client, GatewayIntentBits } = require('discord.js'); const dscaffold = require('dscaffold').default; require('dotenv').config(); const path = require('path'); ${this.config.features.logging ? "const { logger } = require('./utils/logger');" : ''} ${this.config.features.database ? "const { connectDB } = require('./utils/database');" : ''} const client = new Client({ intents: [${intentsArray}], }); // Initialize dscaffold and load commands/events async function initialize() { try { // Load commands from the commands directory (supports nested folders) await dscaffold.loadCommands(client, path.join(__dirname, 'commands')); // Load events from the events directory await dscaffold.loadEvents(client, path.join(__dirname, 'events')); ${this.config.features.database ? ' // Connect to database\n await connectDB();' : ''} // Login to Discord await client.login(process.env.DISCORD_TOKEN); } catch (error) { console.error('❌ Failed to initialize bot:', error); process.exit(1); } } // Handle command interactions client.on('messageCreate', async (message) => { if (message.author.bot) return; const prefix = process.env.PREFIX || '${this.config.botSettings.prefix}'; if (!message.content.startsWith(prefix)) return; const args = message.content.slice(prefix.length).trim().split(/ +/); const commandName = args.shift()?.toLowerCase(); if (!commandName) return; const command = dscaffold.getCommand(commandName); if (!command) return; try { await command.execute(message, args); } catch (error) { console.error('❌ Error executing command:', error); message.reply('There was an error executing that command!'); } }); // Handle slash command interactions client.on('interactionCreate', async (interaction) => { if (!interaction.isChatInputCommand()) return; const command = dscaffold.getCommand(interaction.commandName); if (!command) return; try { await command.execute(interaction); } catch (error) { console.error('❌ Error executing slash command:', error); await interaction.reply({ content: 'There was an error executing that command!', ephemeral: true }); } }); // Start the bot initialize();`; } } async generateProjectStructure(targetPath) { const directories = [ 'src', 'src/commands', 'src/events', 'config', ]; if (this.config.features.database) { directories.push('src/models'); } if (this.config.features.logging) { directories.push('logs'); } for (const dir of directories) { await (0, utils_1.ensureDir)(path_1.default.join(targetPath, dir)); } } async generateConfigFiles(targetPath) { // Generate .env file const envContent = this.getEnvTemplate(); await (0, utils_1.writeFile)(path_1.default.join(targetPath, '.env'), envContent); // Generate .env.example const envExampleContent = this.getEnvExampleTemplate(); await (0, utils_1.writeFile)(path_1.default.join(targetPath, '.env.example'), envExampleContent); // Generate config file const isTs = this.config.language === 'typescript'; const extension = isTs ? 'ts' : 'js'; const configTemplate = isTs ? this.getConfigTsTemplate() : this.getConfigJsTemplate(); const content = this.templateRenderer.render(configTemplate, { prefix: this.config.botSettings.prefix, intents: this.config.botSettings.intents, }); await (0, utils_1.writeFile)(path_1.default.join(targetPath, `config/bot.${extension}`), content); } async generateExampleFiles(targetPath) { const isTs = this.config.language === 'typescript'; const extension = isTs ? 'ts' : 'js'; // Generate example command const commandTemplate = isTs ? this.getExampleCommandTsTemplate() : this.getExampleCommandJsTemplate(); const commandContent = this.templateRenderer.render(commandTemplate, { prefix: this.config.botSettings.prefix, }); await (0, utils_1.writeFile)(path_1.default.join(targetPath, `src/commands/ping.${extension}`), commandContent); // Generate example event const eventTemplate = isTs ? this.getExampleEventTsTemplate() : this.getExampleEventJsTemplate(); const eventContent = this.templateRenderer.render(eventTemplate, this.config); await (0, utils_1.writeFile)(path_1.default.join(targetPath, `src/events/ready.${extension}`), eventContent); } async generateEslintConfig(targetPath) { const template = this.getEslintConfigTemplate(); const content = this.templateRenderer.render(template, { isTypeScript: this.config.language === 'typescript', }); await (0, utils_1.writeFile)(path_1.default.join(targetPath, '.eslintrc.json'), content); } async generatePrettierConfig(targetPath) { const template = this.getPrettierConfigTemplate(); await (0, utils_1.writeFile)(path_1.default.join(targetPath, '.prettierrc'), template); } async generateDockerFiles(targetPath) { const dockerfileTemplate = this.getDockerfileTemplate(); const dockerfileContent = this.templateRenderer.render(dockerfileTemplate, { isTypeScript: this.config.language === 'typescript', }); await (0, utils_1.writeFile)(path_1.default.join(targetPath, 'Dockerfile'), dockerfileContent); const dockerIgnoreTemplate = this.getDockerIgnoreTemplate(); await (0, utils_1.writeFile)(path_1.default.join(targetPath, '.dockerignore'), dockerIgnoreTemplate); } async generateReadme(targetPath) { const template = this.getReadmeTemplate(); const content = this.templateRenderer.render(template, { name: this.config.name, language: this.config.language, prefix: this.config.botSettings.prefix, hasDatabase: this.config.features.database, hasDocker: this.config.features.docker, }); await (0, utils_1.writeFile)(path_1.default.join(targetPath, 'README.md'), content); } // Template methods (simplified for brevity - these would load from actual template files) getPackageJsonTemplate() { return `{ "name": "{{name}}", "version": "1.0.0", "description": "A Discord bot built with Discord.js", "main": "{{#isTypeScript}}dist/index.js{{/isTypeScript}}{{^isTypeScript}}src/index.js{{/isTypeScript}}", "scripts": { {{#isTypeScript}}"build": "tsc", "start": "node dist/index.js", "dev": "ts-node-dev --respawn --transpile-only src/index.ts", "watch": "tsc --watch",{{/isTypeScript}} {{^isTypeScript}}"start": "node src/index.js", "dev": "nodemon src/index.js",{{/isTypeScript}} {{#hasEslint}}"lint": "eslint {{#isTypeScript}}src/**/*.ts{{/isTypeScript}}{{^isTypeScript}}src/**/*.js{{/isTypeScript}}", "lint:fix": "eslint {{#isTypeScript}}src/**/*.ts{{/isTypeScript}}{{^isTypeScript}}src/**/*.js{{/isTypeScript}} --fix",{{/hasEslint}} {{#hasPrettier}}"format": "prettier --write {{#isTypeScript}}src/**/*.ts{{/isTypeScript}}{{^isTypeScript}}src/**/*.js{{/isTypeScript}}",{{/hasPrettier}} "test": "echo \\"Error: no test specified\\" && exit 1" }, "dependencies": { "discord.js": "^14.14.1", "dotenv": "^16.4.5"{{#hasDatabase}}, "mongoose": "^8.1.1"{{/hasDatabase}}{{#hasLogging}}, "winston": "^3.11.0"{{/hasLogging}} }, "devDependencies": { {{#isTypeScript}}"@types/node": "^20.11.24", "ts-node": "^10.9.2", "ts-node-dev": "^2.0.0", "typescript": "^5.3.3"{{/isTypeScript}} {{^isTypeScript}}"nodemon": "^3.0.3"{{/isTypeScript}} {{#hasEslint}}{{#isTypeScript}},{{/isTypeScript}}{{^isTypeScript}}{{#hasPrettier}},{{/hasPrettier}}{{/isTypeScript}} "eslint": "^8.56.0"{{#isTypeScript}}, "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0"{{/isTypeScript}}{{/hasEslint}} {{#hasPrettier}}{{#hasEslint}},{{/hasEslint}}{{^hasEslint}}{{#isTypeScript}},{{/isTypeScript}}{{^isTypeScript}},{{/isTypeScript}}{{/hasEslint}} "prettier": "^3.2.5"{{#hasEslint}}, "eslint-config-prettier": "^9.1.0"{{/hasEslint}}{{/hasPrettier}} }, "keywords": ["discord", "bot", "discord.js"], "author": "", "license": "MIT" }`; } getTsConfigTemplate() { return `{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "lib": ["ES2020"], "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "moduleResolution": "node", "types": ["node"] }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] }`; } getMainTsTemplate() { return `import { Client, GatewayIntentBits } from 'discord.js'; import dotenv from 'dotenv'; import path from 'path'; import fs from 'fs'; {{#hasLogging}}import { logger } from './utils/logger';{{/hasLogging}} {{#hasDatabase}}import { connectDB } from './utils/database';{{/hasDatabase}} dotenv.config(); const client = new Client({ intents: [{{#intents}}GatewayIntentBits.{{.}},{{/intents}}], }); // Load commands const commandsPath = path.join(__dirname, 'commands'); const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.ts') || file.endsWith('.js')); for (const file of commandFiles) { const command = require(path.join(commandsPath, file)); // Add command loading logic here } // Load events const eventsPath = path.join(__dirname, 'events'); const eventFiles = fs.readdirSync(eventsPath).filter(file => file.endsWith('.ts') || file.endsWith('.js')); for (const file of eventFiles) { const event = require(path.join(eventsPath, file)); if (event.once) { client.once(event.name, (...args) => event.execute(...args)); } else { client.on(event.name, (...args) => event.execute(...args)); } } {{#hasDatabase}} // Connect to database connectDB(); {{/hasDatabase}} client.login(process.env.DISCORD_TOKEN);`; } getMainJsTemplate() { return `const { Client, GatewayIntentBits } = require('discord.js'); require('dotenv').config(); const path = require('path'); const fs = require('fs'); {{#hasLogging}}const { logger } = require('./utils/logger');{{/hasLogging}} {{#hasDatabase}}const { connectDB } = require('./utils/database');{{/hasDatabase}} const client = new Client({ intents: [{{#intents}}GatewayIntentBits.{{.}},{{/intents}}], }); // Load commands const commandsPath = path.join(__dirname, 'commands'); const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js')); for (const file of commandFiles) { const command = require(path.join(commandsPath, file)); // Add command loading logic here } // Load events const eventsPath = path.join(__dirname, 'events'); const eventFiles = fs.readdirSync(eventsPath).filter(file => file.endsWith('.js')); for (const file of eventFiles) { const event = require(path.join(eventsPath, file)); if (event.once) { client.once(event.name, (...args) => event.execute(...args)); } else { client.on(event.name, (...args) => event.execute(...args)); } } {{#hasDatabase}} // Connect to database connectDB(); {{/hasDatabase}} client.login(process.env.DISCORD_TOKEN);`; } getEnvTemplate() { return `DISCORD_TOKEN=your_bot_token_here CLIENT_ID=your_client_id_here {{#hasDatabase}} DATABASE_URL=mongodb://localhost:27017/discord_bot {{/hasDatabase}}`; } getEnvExampleTemplate() { return `DISCORD_TOKEN=your_bot_token_here CLIENT_ID=your_client_id_here {{#hasDatabase}} DATABASE_URL=mongodb://localhost:27017/discord_bot {{/hasDatabase}}`; } getConfigTsTemplate() { return `export const config = { prefix: '{{prefix}}', token: process.env.DISCORD_TOKEN, clientId: process.env.CLIENT_ID, {{#hasDatabase}}databaseUrl: process.env.DATABASE_URL,{{/hasDatabase}} };`; } getConfigJsTemplate() { return `module.exports = { prefix: '{{prefix}}', token: process.env.DISCORD_TOKEN, clientId: process.env.CLIENT_ID, {{#hasDatabase}}databaseUrl: process.env.DATABASE_URL,{{/hasDatabase}} };`; } getExampleCommandTsTemplate() { return `import { Message } from 'discord.js'; module.exports = { name: 'ping', description: 'Test bot latency', category: 'utility', async execute(message: Message, args: string[]) { const sent = await message.reply('🏓 Pinging...'); const latency = sent.createdTimestamp - message.createdTimestamp; const apiLatency = Math.round(message.client.ws.ping); await sent.edit(\`🏓 Pong!\\n📡 Latency: \${latency}ms\\n💓 API Latency: \${apiLatency}ms\`); }, };`; } getExampleCommandJsTemplate() { return `module.exports = { name: 'ping', description: 'Test bot latency', category: 'utility', async execute(message, args) { const sent = await message.reply('🏓 Pinging...'); const latency = sent.createdTimestamp - message.createdTimestamp; const apiLatency = Math.round(message.client.ws.ping); await sent.edit(\`🏓 Pong!\\n📡 Latency: \${latency}ms\\n💓 API Latency: \${apiLatency}ms\`); }, };`; } getExampleEventTsTemplate() { return `import { Client } from 'discord.js'; module.exports = { name: 'ready', once: true, execute(client: Client) { console.log(\`✅ \${client.user?.tag} is online!\`); console.log(\`📊 Serving \${client.guilds.cache.size} guilds with \${client.users.cache.size} users\`); // Set bot activity client.user?.setActivity('Powered by Dscaffold', { type: 'PLAYING' }); }, };`; } getExampleEventJsTemplate() { return `module.exports = { name: 'ready', once: true, execute(client) { console.log(\`✅ \${client.user?.tag} is online!\`); console.log(\`📊 Serving \${client.guilds.cache.size} guilds with \${client.users.cache.size} users\`); // Set bot activity client.user?.setActivity('Powered by Dscaffold', { type: 'PLAYING' }); }, };`; } getEslintConfigTemplate() { return `{ "env": { "node": true, "es2021": true }, "extends": [ "eslint:recommended"{{#isTypeScript}}, "@typescript-eslint/recommended"{{/isTypeScript}} ], {{#isTypeScript}}"parser": "@typescript-eslint/parser", "parserOptions": { "ecmaVersion": 12, "sourceType": "module" }, "plugins": ["@typescript-eslint"],{{/isTypeScript}} "rules": { "indent": ["error", 2], "linebreak-style": ["error", "unix"], "quotes": ["error", "single"], "semi": ["error", "always"] } }`; } getPrettierConfigTemplate() { return `{ "semi": true, "trailingComma": "es5", "singleQuote": true, "printWidth": 80, "tabWidth": 2 }`; } getDockerfileTemplate() { return `FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . {{#isTypeScript}} RUN npm run build CMD ["npm", "start"] {{/isTypeScript}} {{^isTypeScript}} CMD ["npm", "start"] {{/isTypeScript}}`; } getDockerIgnoreTemplate() { return `node_modules npm-debug.log .git .gitignore README.md .env .nyc_output coverage .cache {{#isTypeScript}}src{{/isTypeScript}}`; } getReadmeTemplate() { return `# {{name}} A Discord bot built with Discord.js{{#isTypeScript}} and TypeScript{{/isTypeScript}}, powered by **Dscaffold** for dynamic command and event loading. ## ✨ Features - 🚀 **Dynamic Loading**: Commands and events are automatically loaded from directories - 📁 **Nested Support**: Organize commands in subfolders (e.g., \`admin/\`, \`moderation/\`) - 🔥 **Hot Reload**: Commands can be reloaded without restarting the bot - 📝 **TypeScript Ready**: Full TypeScript support with proper typing - 🎯 **Category System**: Automatic command categorization ## 🚀 Quick Start 1. **Install dependencies:** \`\`\`bash npm install \`\`\` 2. **Configure environment:** \`\`\`bash cp .env.example .env # Edit .env with your bot token \`\`\` 3. **Start the bot:** \`\`\`bash {{#isTypeScript}}npm run dev{{/isTypeScript}}{{^isTypeScript}}npm run dev{{/isTypeScript}} \`\`\` ## 📁 Project Structure \`\`\` {{name}}/ ├── src/ │ ├── commands/ # Bot commands (supports nested folders) │ │ ├── utility/ # Example: utility commands │ │ ├── admin/ # Example: admin commands │ │ └── ping.{{#isTypeScript}}ts{{/isTypeScript}}{{^isTypeScript}}js{{/isTypeScript}} # Example command │ ├── events/ # Discord event handlers │ │ └── ready.{{#isTypeScript}}ts{{/isTypeScript}}{{^isTypeScript}}js{{/isTypeScript}} # Example event {{#hasDatabase}}│ ├── models/ # Database models{{/hasDatabase}} │ └── index.{{#isTypeScript}}ts{{/isTypeScript}}{{^isTypeScript}}js{{/isTypeScript}} # Main bot file ├── config/ │ └── bot.{{#isTypeScript}}ts{{/isTypeScript}}{{^isTypeScript}}js{{/isTypeScript}} # Bot configuration └── .env # Environment variables \`\`\` ## 🎮 Commands - \`{{prefix}}ping\` - Test bot latency and connection ## 🔧 Development ### Adding Commands Create a new file in \`src/commands/\` (or any subfolder): \`\`\`{{#isTypeScript}}typescript{{/isTypeScript}}{{^isTypeScript}}javascript{{/isTypeScript}} {{#isTypeScript}}// src/commands/utility/info.ts import { Message } from 'discord.js'; module.exports = { name: 'info', description: 'Get bot information', category: 'utility', async execute(message: Message, args: string[]) { await message.reply('Bot info here!'); }, };{{/isTypeScript}}{{^isTypeScript}}// src/commands/utility/info.js module.exports = { name: 'info', description: 'Get bot information', category: 'utility', async execute(message, args) { await message.reply('Bot info here!'); }, };{{/isTypeScript}} \`\`\` ### Adding Events Create a new file in \`src/events/\`: \`\`\`{{#isTypeScript}}typescript{{/isTypeScript}}{{^isTypeScript}}javascript{{/isTypeScript}} {{#isTypeScript}}// src/events/messageCreate.ts import { Message } from 'discord.js'; module.exports = { name: 'messageCreate', execute(message: Message) { // Handle message events }, };{{/isTypeScript}}{{^isTypeScript}}// src/events/messageCreate.js module.exports = { name: 'messageCreate', execute(message) { // Handle message events }, };{{/isTypeScript}} \`\`\` ### Using Dscaffold API \`\`\`{{#isTypeScript}}typescript{{/isTypeScript}}{{^isTypeScript}}javascript{{/isTypeScript}} {{#isTypeScript}}import dscaffold from 'dscaffold'; // Get a command const command = dscaffold.getCommand('ping'); // Get commands by category const utilityCommands = dscaffold.getCommandsByCategory('utility'); // Get all categories const categories = dscaffold.getCategories(); // Reload commands (useful for development) await dscaffold.reloadCommands(client, './src/commands');{{/isTypeScript}}{{^isTypeScript}}const dscaffold = require('dscaffold').default; // Get a command const command = dscaffold.getCommand('ping'); // Get commands by category const utilityCommands = dscaffold.getCommandsByCategory('utility'); // Get all categories const categories = dscaffold.getCategories(); // Reload commands (useful for development) await dscaffold.reloadCommands(client, './src/commands');{{/isTypeScript}} \`\`\` ## 📜 Scripts {{#isTypeScript}}- \`npm run dev\` - Start with auto-reload (development) - \`npm run build\` - Build TypeScript to JavaScript - \`npm start\` - Start the compiled bot (production){{/isTypeScript}}{{^isTypeScript}}- \`npm run dev\` - Start with auto-reload (development) - \`npm start\` - Start the bot{{/isTypeScript}} {{#hasDocker}}## 🐳 Docker \`\`\`bash # Build and run with Docker docker build -t {{name}} . docker run -d --name {{name}} --env-file .env {{name}} \`\`\`{{/hasDocker}} ## 🔗 Powered By - **[Dscaffold](https://github.com/dscaffold/dscaffold)** - Dynamic Discord bot framework - **[Discord.js](https://discord.js.org/)** - Discord API library ## 📝 License MIT`; } } exports.ProjectGenerator = ProjectGenerator; //# sourceMappingURL=ProjectGenerator.js.map