diff --git a/src/index.ts b/src/index.ts old mode 100644 new mode 100755 index 82393f3..c41bef5 --- a/src/index.ts +++ b/src/index.ts @@ -9,11 +9,13 @@ import { fileURLToPath } from 'url'; import { checkDockerFolder, checkPrerequisites, + createFile, dockerCompose, dockerExec, downloadAndExtractTemplate, generateComposeFiles, parseServices, + validatePluginName, validateProjectName, } from './lib.js'; @@ -245,6 +247,112 @@ program dockerCompose(`${composeArgs} down -v`); }); + +// CLI command to create a new plugin +program + .command('plugin ') + .description('Create a new Hexabot plugin') + .action((pluginName: string) => { + // Validate plugin name + if (!validatePluginName(pluginName)) { + console.error( + chalk.red( + 'Invalid plugin name. It should contain only lowercase letters, numbers, and dashes.', + ), + ); + process.exit(1); + } + + // Define the plugins folder path + const pluginsFolder = path.join(process.cwd(), 'plugins'); + + // Ensure the plugins folder exists + if (!fs.existsSync(pluginsFolder)) { + fs.mkdirSync(pluginsFolder, { recursive: true }); + } + + const pluginPath = path.join(pluginsFolder, pluginName); + + // Check if the plugin folder already exists + if (fs.existsSync(pluginPath)) { + console.error(chalk.red(`A plugin named "${pluginName}" already exists in the plugins folder.`)); + process.exit(1); + } + + // Create plugin folder + fs.mkdirSync(pluginPath, { recursive: true }); + + // Define file structure and content + const files = [ + { + path: 'README.md', + content: `# ${pluginName}\n\nPlugin documentation.`, + }, + { + path: 'index.plugin.ts', + content: `// Main entry point for the ${pluginName} plugin\n\nexport const plugin = {};`, + }, + { + path: 'package.json', + content: JSON.stringify( + { + name: pluginName, + version: '1.0.0', + author: 'Your Name', + description: `${pluginName} plugin for Hexabot.`, + dependencies: {}, + }, + null, + 2, + ), + }, + { + path: 'settings.ts', + content: `// Settings for the ${pluginName} plugin\n\nexport const settings = {};`, + }, + { + path: 'i18n/en/title.json', + content: JSON.stringify( + { + title: `${pluginName} Plugin`, + }, + null, + 2, + ), + }, + { + path: 'i18n/en/label.json', + content: JSON.stringify( + { + message: `Message`, + }, + null, + 2, + ), + }, + { + path: 'i18n/en/help.json', + content: JSON.stringify( + { + message: `The message that will be sent back.`, + }, + null, + 2, + ), + }, + ]; + + // Create files + files.forEach((file) => { + const filePath = path.join(pluginPath, file.path); + createFile(filePath, file.content); + }); + + console.log(chalk.green(`🎉 Plugin Sturcture ${pluginName} created successfully.`)); + console.log(chalk.gray(`Next steps:`)); + console.log(chalk.yellow(`>> Implement your plugin Logic 👨🏻‍💻 `)); + }); + // Parse arguments program.parse(process.argv); diff --git a/src/lib.ts b/src/lib.ts index 6f7b180..602b5a8 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -213,3 +213,15 @@ export const downloadAndExtractTemplate = async ( throw new Error(`Failed to download template from GitHub`); } }; + +// Function to validate the plugin name +export const validatePluginName = (name: string): boolean => /^[a-z0-9]+(-[a-z0-9]+)*$/.test(name); + +// Function to create a file with specified content +export const createFile = (filePath: string, content: string): void => { + const dir = path.dirname(filePath); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + fs.writeFileSync(filePath, content, 'utf8'); +};