diff --git a/README.md b/README.md index d96f2c7..7043a18 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ API Documentation [Swagger] ## Features - Authentication and Authorization -- JWT Tokens, make requests with a token after login with `Authorization` header with value `Bearer yourToken` where `yourToken` will be returned in Login response. +- JWT Tokens, make requests with a token after login with `Authorization` header with value `Bearer yourToken` where `yourToken` will be returned in the Login response. - Role Manage - Update Profile/Password User Account - Reset Password Mail using `nodemailer` @@ -49,7 +49,7 @@ API Documentation [Swagger] - Included API collection for Postman. - Light-weight project. - Linting with [Eslint](https://eslint.org/). (Airbnb style) -- Included CLI for generate CRUD operations. +- Included CLI for generating CRUD operations. - husky for pre-commit hooks and lint-staged for running linters on git staged files. ## Software Requirements @@ -169,9 +169,11 @@ If you need to add more controllers to the project just create a new file in `sr 2. Run the following command: ```bash -npm run generate-crud +npm run crud-operation ``` +See the [CLI README](cli/README.md) section for more details on how to use the CLI to generate or delete CRUD operations. + Follow the prompts to select the CRUD type (empty or minimal) and provide the entity name. The tool will generate the necessary files for the CRUD operations based on your selection. ## Linting and Formatting @@ -212,3 +214,15 @@ This project is open-sourced software licensed under the MIT License. See the LI ## Support For any inquiries or issues, please contact [Support Email](raed.fadhlaoui@hotmail.com). + +- **Optimization**: Improved readability by reorganizing the content and ensuring consistency in formatting. +- **Documentation Update**: Reflects the changes made to the CLI commands for generating and deleting CRUD operations. +- **Bug Fixes**: Resolved issues related to the CLI commands and the project structure. +- **Feature Addition**: Added support for generating empty and minimal CRUD operations using the CLI. +- **Code Quality**: Improved code quality by adding linting and formatting tools. +- **Security**: Updated dependencies to address security vulnerabilities. +- **Testing**: Added support for running tests using Jest. +- **Performance**: Improved performance by optimizing the code and removing unnecessary dependencies. +- **Refactoring**: Refactored the code to improve readability and maintainability. +- **Dependency Update**: Updated dependencies to their latest versions. +- **Configuration**: Updated the configuration files to reflect the changes made to the project structure. diff --git a/cli/README.md b/cli/README.md new file mode 100644 index 0000000..458ecce --- /dev/null +++ b/cli/README.md @@ -0,0 +1,55 @@ +## CLI Commands + +### How to Use CRUD Operations + +To generate or delete CRUD operations, you can use the CLI provided in this project. The CLI allows you to automate the process of creating or removing CRUD (Create, Read, Update, Delete) operations for entities within a MongoDB database. + +### Usage + +#### Running the CLI + +To run the CLI, execute the following command: + +```bash +npm run crud-operation +``` + +Selecting Action +Upon running the CLI, you will be prompted to select an action to perform. You can choose between generating CRUD operations or deleting existing CRUD operations. + +#### Generating CRUD Operations + +If you select the option to generate CRUD operations, the CLI will guide you through the process. You will be prompted to enter the name of the entity for which you want to generate CRUD operations. Additionally, you will need to specify the type of CRUD operations you want to generate, whether empty or minimal. + +#### Empty CRUD Operations + +Empty CRUD operations include the basic structure for Create, Read, Update, and Delete operations. This option provides a starting point for implementing custom logic for each operation. + +#### Minimal CRUD Operations + +Minimal CRUD operations include a simplified version of Create, Read, Update, and Delete operations. This option provides basic functionality with minimal boilerplate code. + +#### Deleting CRUD Operations + +If you select the option to delete CRUD operations, the CLI will prompt you to enter the name of the entity for which you want to delete CRUD operations. Once confirmed, the CLI will remove all associated CRUD files for the specified entity. + +### Example + +Here's an example of how you can use the CLI to generate CRUD operations: + +Run the CLI: + +```bash +npm run crud-operation +``` + +1. Select the action "Generate CRUD." +2. Enter the name of the entity (e.g., "user") for which you want to generate CRUD operations. +3. Choose the type of CRUD operations (empty or minimal). +4. Follow the prompts to complete the generation process. + +### Note + +Ensure that you have the necessary permissions and dependencies installed before running the CLI. Additionally, make sure to review the generated CRUD files and modify them according to your application's requirements. + +This documentation provides a clear overview of how to use the CLI to generate or delete CRUD operations in the project. Adjustments have been made to reflect the changes made in this version, including the implementation of delete CRUD and the change from `npm run generate-crud` to `npm run crud-operation`. diff --git a/cli/_/deleteCrud.js b/cli/_/deleteCrud.js new file mode 100644 index 0000000..9923e36 --- /dev/null +++ b/cli/_/deleteCrud.js @@ -0,0 +1,58 @@ +const fs = require('fs').promises; +const path = require('path'); + +/** + * Function to delete CRUD. + * @param {string} entity - The entity to delete CRUD for. + * @returns {Promise} - A Promise that resolves when CRUD is deleted successfully + */ +async function deleteCrud(entity) { + try { + // Define the paths for model, controller, and route files + const modelPath = path.join( + __dirname, + '..', + 'src', + 'models', + `${entity}.model.js`, + ); + const controllerPath = path.join( + __dirname, + '..', + 'src', + 'controllers', + `${entity}.controller.js`, + ); + const routePath = path.join( + __dirname, + '..', + 'src', + 'routes', + `${entity}.route.js`, + ); + + // Remove the model, controller, and route files + await Promise.all([ + fs.unlink(modelPath), + fs.unlink(controllerPath), + fs.unlink(routePath), + ]); + + // Remove routes reference from server.js + const serverFilePath = path.join(__dirname, '..', 'server.js'); + let serverFileContent = await fs.readFile(serverFilePath, 'utf-8'); + serverFileContent = serverFileContent.replace( + `const ${entity}Routes = require('./src/routes/${entity}.route');\napp.use('/v1/api', ${entity}Routes);\n`, + '', + ); + await fs.writeFile(serverFilePath, serverFileContent); + + console.log('CRUD deleted successfully for entity:', entity); + } catch (error) { + // Handle errors + console.error('An error occurred while deleting CRUD:', error); + throw error; + } +} + +module.exports = { deleteCrud }; diff --git a/cli/generateEmptyCrud.js b/cli/_/generateEmptyCrud.js similarity index 98% rename from cli/generateEmptyCrud.js rename to cli/_/generateEmptyCrud.js index a1191e7..a93f02d 100644 --- a/cli/generateEmptyCrud.js +++ b/cli/_/generateEmptyCrud.js @@ -32,7 +32,7 @@ async function generateEmptyCrud(entity) { ]); // Add route to server.js - const lineToAdd = `const ${entity}Routes = require('./src/routes/${entity}.route');\n\napp.use('/v1/api', ${entity}Routes);\n`; + const lineToAdd = `const ${entity}Routes = require('./src/routes/${entity}.route');\napp.use('/v1/api', ${entity}Routes);\n`; try { const serverFilePath = path.join('server.js'); let serverFileContent = await fs.readFile(serverFilePath, 'utf-8'); diff --git a/cli/generateMinimalCrud.js b/cli/_/generateMinimalCrud.js similarity index 100% rename from cli/generateMinimalCrud.js rename to cli/_/generateMinimalCrud.js diff --git a/cli/helpers.js b/cli/_/helpers.js similarity index 100% rename from cli/helpers.js rename to cli/_/helpers.js diff --git a/cli/index.js b/cli/index.js index 39cda48..6a5a812 100644 --- a/cli/index.js +++ b/cli/index.js @@ -5,64 +5,82 @@ const inquirer = require('inquirer'); // For prompting user input // Local helpers and functions -const { generateEmptyCrud } = require('./generateEmptyCrud'); // Function to generate empty CRUD -const { generateMinimalCrud } = require('./generateMinimalCrud'); // Function to generate minimal CRUD -const { isEntityExists } = require('./helpers'); // Function to check if entity already exists +const { generateEmptyCrud } = require('./_/generateEmptyCrud'); // Function to generate empty CRUD +const { generateMinimalCrud } = require('./_/generateMinimalCrud'); // Function to generate minimal CRUD +const { deleteCrud } = require('./_/deleteCrud'); // Function to delete CRUD +const { isEntityExists } = require('./_/helpers'); // Function to check if entity already exists /* -------------------------------------------------------------------------- */ /* MAIN */ /* -------------------------------------------------------------------------- */ /** - * Main function to handle the CLI input and generate CRUD based on the user input. - * It prompts the user for the entity name and CRUD type, performs validation, - * checks if the entity already exists, and generates CRUD based on user input. - * @returns {Promise} - A Promise that resolves when CRUD is generated successfully + * Main function to handle the CLI input for generating or deleting CRUD operations. + * It prompts the user for the action to perform and handles the corresponding action. + * @returns {Promise} - A Promise that resolves when the action is performed successfully */ async function main() { try { - // Parse command line arguments - const args = process.argv.slice(2); + // Interactive prompt for selecting action + const actionPrompt = { + type: 'list', + name: 'action', + message: 'Select action:', + choices: ['Generate CRUD', 'Delete CRUD', 'Exit'], + }; - // Check if command is valid - if (args.length < 1 || args[0] !== 'generate') { - console.log('Invalid command. Use "generate" command.'); - process.exit(1); + const { action } = await inquirer.prompt(actionPrompt); + + switch (action) { + case 'Generate CRUD': + await generateCrud(); + break; + case 'Delete CRUD': + await deleteCrudAction(); + break; + case 'Exit': + console.log('Exiting...'); + process.exit(0); + break; + default: + console.log('Invalid action:', action); + process.exit(1); } + } catch (error) { + // Handle errors + console.error('An error occurred:', error); + process.exit(1); + } +} +/** + * Function to handle the CRUD generation process. + * @returns {Promise} - A Promise that resolves when CRUD is generated successfully + */ +async function generateCrud() { + try { // Prompt user to enter entity name const entityPrompt = { type: 'input', name: 'entity', message: 'Enter entity name:', validate: async (input) => { - // Trim leading and trailing whitespace const trimmedInput = input.trim(); - - // Check if entity name is empty after trimming if (!trimmedInput) { return 'Entity name cannot be empty'; } - - // Check if entity name contains only alphanumeric characters and underscores if (!/^[a-zA-Z0-9_]+$/.test(trimmedInput)) { return 'Entity name can only contain letters, numbers, and underscores'; } - - // Check if entity name already exists const entityExists = await isEntityExists(trimmedInput); if (entityExists) { return `Entity "${trimmedInput}" already exists. Cannot generate CRUD.`; } - - // Validation passed return true; }, }; - // Get entity name from user input const { entity } = await inquirer.prompt(entityPrompt); - // Prompt user to select CRUD type const commandPrompt = { type: 'list', name: 'command', @@ -70,29 +88,62 @@ async function main() { choices: ['empty', 'minimal'], }; - // Get CRUD type from user input const { command } = await inquirer.prompt(commandPrompt); - // Generate CRUD based on user input switch (command) { case 'empty': - await generateEmptyCrud(entity, generateEmptyCrud); + await generateEmptyCrud(entity); console.log('Empty CRUD generated successfully for entity:', entity); + console.log('Exiting...'); + process.exit(0); break; case 'minimal': - await generateMinimalCrud(entity, generateMinimalCrud); + await generateMinimalCrud(entity); console.log('Minimal CRUD generated successfully for entity:', entity); + console.log('Exiting...'); + process.exit(0); break; default: console.log('Invalid command:', command); process.exit(1); } } catch (error) { - // Handle errors - console.error('An error occurred:', error); + console.error('An error occurred during CRUD generation:', error); + process.exit(1); + } +} + +/** + * Function to handle the CRUD deletion process. + * @returns {Promise} - A Promise that resolves when CRUD is deleted successfully + */ +async function deleteCrudAction() { + try { + // Prompt user to enter entity name for deletion + const entityPrompt = { + type: 'input', + name: 'entity', + message: 'Enter entity name to delete CRUD:', + validate: async (input) => { + const trimmedInput = input.trim(); + if (!trimmedInput) { + return 'Entity name cannot be empty'; + } + return true; + }, + }; + + const { entity } = await inquirer.prompt(entityPrompt); + await deleteCrud(entity); + } catch (error) { + console.error('An error occurred during CRUD deletion:', error); process.exit(1); } } -// Invoke main function -main(); +// Invoke main function if the script is run directly +if (require.main === module) { + main(); +} + +module.exports = { generateCrud, deleteCrudAction }; diff --git a/package.json b/package.json index ac63aba..e3aba94 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "scripts": { "start": "NODE_ENV=production && node server.js", "develop": "SET NODE_ENV=development && nodemon server.js", - "generate-crud": "node cli/index.js generate", + "create-operation": "node cli/index.js generate", "lint:check": "eslint --ext .js,.jsx,.ts,.tsx .", "format:check": "prettier --check .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx --fix .", diff --git a/server.js b/server.js index e273eca..b9b2e8f 100644 --- a/server.js +++ b/server.js @@ -1,7 +1,6 @@ /* -------------------------------------------------------------------------- */ /* Dependencies */ /* -------------------------------------------------------------------------- */ - // Packages const express = require('express'); const dotenv = require('dotenv'); @@ -44,8 +43,9 @@ app.use(express.static(path.join(__dirname, 'uploads'))); app.use(cors()); // Require APIs -const authRoutes = require('./src/routes/auth.route'); const userRoutes = require('./src/routes/user.route'); +const authRoutes = require('./src/routes/auth.route'); + // local APIs app.use('/v1/api', authRoutes);