create-jerry 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +225 -55
  2. package/Templates/base/js/app.js +19 -0
  3. package/Templates/base/js/config/index.js +18 -0
  4. package/Templates/base/js/middlewares/error.middleware.js +8 -0
  5. package/Templates/base/js/routes/index.js +12 -0
  6. package/Templates/base/js/server.js +21 -0
  7. package/Templates/base/js/utils/asyncHandler.js +5 -0
  8. package/Templates/base/ts/app.ts +19 -0
  9. package/Templates/base/ts/config/index.ts +18 -0
  10. package/Templates/base/ts/middlewares/error.middleware.ts +15 -0
  11. package/Templates/base/ts/routes/index.ts +12 -0
  12. package/Templates/base/ts/server.ts +21 -0
  13. package/Templates/base/ts/tsconfig.json +18 -0
  14. package/Templates/base/ts/utils/asyncHandler.ts +5 -0
  15. package/Templates/db/mongodb/js/db.js +39 -0
  16. package/Templates/db/mongodb/ts/db.ts +50 -0
  17. package/Templates/db/mysql/js/db.js +58 -0
  18. package/Templates/db/mysql/ts/db.ts +72 -0
  19. package/Templates/modules/ai/js/ai.controller.js +30 -0
  20. package/Templates/modules/ai/js/ai.provider.js +32 -0
  21. package/Templates/modules/ai/js/ai.routes.js +8 -0
  22. package/Templates/modules/ai/js/ai.service.js +16 -0
  23. package/Templates/modules/ai/ts/ai.controller.ts +31 -0
  24. package/Templates/modules/ai/ts/ai.provider.ts +30 -0
  25. package/Templates/modules/ai/ts/ai.routes.ts +8 -0
  26. package/Templates/modules/ai/ts/ai.service.ts +16 -0
  27. package/Templates/modules/user/js/user.controller.js +46 -0
  28. package/Templates/modules/user/js/user.provider.js +25 -0
  29. package/Templates/modules/user/js/user.routes.js +12 -0
  30. package/Templates/modules/user/js/user.service.js +21 -0
  31. package/Templates/modules/user/ts/user.controller.ts +27 -0
  32. package/Templates/modules/user/ts/user.provider.ts +25 -0
  33. package/Templates/modules/user/ts/user.routes.ts +12 -0
  34. package/Templates/modules/user/ts/user.service.ts +21 -0
  35. package/fileCreator.js +140 -31
  36. package/folderCreator.js +15 -0
  37. package/index.js +85 -76
  38. package/installer.js +11 -13
  39. package/package.json +5 -3
  40. package/packageJsonCreator.js +45 -72
  41. package/plugins/ai.plugin.js +25 -0
  42. package/plugins/mongodb.plugin.js +15 -0
  43. package/plugins/mysql.plugin.js +15 -0
  44. package/plugins/pluginManager.js +18 -0
  45. package/Templates/db-mongo.js +0 -20
  46. package/Templates/db-sql.js +0 -35
  47. package/Templates/express.js +0 -35
  48. package/folderCreater.js +0 -34
package/index.js CHANGED
@@ -1,116 +1,125 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  import chalk from 'chalk';
4
4
  import chalkAnimation from 'chalk-animation';
5
5
  import inquirer from 'inquirer';
6
- import { installer } from './installer.js';
7
- import {
8
- writeDbFiles,
9
- writeServerFiles,
10
- writeEnvFile
6
+
7
+ import {
8
+ writeCoreFiles,
9
+ writeUserModule,
10
+ writeEnvFile,
11
+ injectRoutes
11
12
  } from './fileCreator.js';
12
- import { createFolders, createProjectDir } from './folderCreater.js';
13
+
14
+ import { createProjectDir } from './folderCreator.js';
13
15
  import { createPackageJson } from './packageJsonCreator.js';
14
16
 
15
- // global responses
17
+ import { mongodbPlugin } from './plugins/mongodb.plugin.js';
18
+ import { mysqlPlugin } from './plugins/mysql.plugin.js';
19
+ import { aiPlugin } from './plugins/ai.plugin.js';
20
+ import { applyPlugins } from './plugins/pluginManager.js';
21
+
22
+ // globals
16
23
  let rawProjectName;
17
24
  let dbchoice;
18
25
  let langchoice;
19
26
 
20
- // timeout
21
- export const sleep = (ms = 1000) => new Promise((r) => setTimeout(r, ms));
27
+ // utils
28
+ const sleep = (ms = 1000) => new Promise((r) => setTimeout(r, ms));
22
29
 
23
- // welcome function
24
30
  async function welcome() {
25
- const rainbowTitle = chalkAnimation.rainbow("\n Welcome to JERRIT \n");
26
- await sleep();
27
- rainbowTitle.stop();
31
+ const rainbowTitle = chalkAnimation.rainbow("\n Welcome to JERRIT \n");
32
+ await sleep();
33
+ rainbowTitle.stop();
28
34
  }
29
35
 
30
- // project name
31
36
  async function askName() {
32
- const res = await inquirer.prompt({
33
- name: 'admin_name',
34
- type: 'input',
35
- message: `${chalk.magentaBright('Project name ?')}`,
36
- default() {
37
- return 'my-app';
38
- },
39
- });
40
-
41
- return res.admin_name;
37
+ const res = await inquirer.prompt({
38
+ name: 'name',
39
+ type: 'input',
40
+ message: 'Project name?',
41
+ default: 'my-app'
42
+ });
43
+ return res.name;
42
44
  }
43
45
 
44
- // database selection
45
46
  async function askDb() {
46
- const res = await inquirer.prompt({
47
- name: 'db_name',
48
- type: 'list',
49
- message: `${chalk.yellowBright('Select your Database ...')}`,
50
- choices: [
51
- { name: chalk.greenBright('MongoDB'), value: 'MongoDB' },
52
- { name: chalk.whiteBright('MySQL'), value: 'MySQL' },
53
- ],
54
- });
55
-
56
- dbchoice = res.db_name;
47
+ const res = await inquirer.prompt({
48
+ name: 'db',
49
+ type: 'list',
50
+ message: 'Select Database',
51
+ choices: ['MongoDB', 'MySQL']
52
+ });
53
+ dbchoice = res.db;
57
54
  }
58
55
 
59
- // language selection
60
56
  async function askLang() {
61
- const res = await inquirer.prompt({
62
- name: 'lang_name',
63
- type: 'list',
64
- message: `${chalk.green('Select your Language...')}`,
65
- choices: [
66
- `${chalk.cyanBright('Typescript')}`,
67
- `${chalk.yellowBright('Javascript')}`,
68
- ],
69
- });
70
-
71
- langchoice = res.lang_name;
57
+ const res = await inquirer.prompt({
58
+ name: 'lang',
59
+ type: 'list',
60
+ message: 'Select Language',
61
+ choices: ['Typescript', 'Javascript']
62
+ });
63
+ langchoice = res.lang;
72
64
  }
73
65
 
74
- // exit function
75
- export async function exit(str) {
76
- const rainbowTitle = chalkAnimation.rainbow(str);
77
- await sleep();
78
- rainbowTitle.stop();
66
+ async function askAI() {
67
+ const res = await inquirer.prompt({
68
+ name: 'ai',
69
+ type: 'confirm',
70
+ message: 'Add AI module?',
71
+ default: false
72
+ });
73
+ return res.ai;
79
74
  }
80
75
 
81
- // Main execution
76
+ // MAIN
82
77
  await welcome();
83
78
 
84
79
  rawProjectName = await askName();
85
-
86
- // Creating root directory
87
80
  createProjectDir(rawProjectName);
88
81
 
89
82
  await askDb();
90
83
  await askLang();
91
84
 
92
- console.log("\n");
85
+ const aiEnabled = await askAI();
93
86
 
94
- // Project setup execution calls
95
- console.log(chalk.whiteBright("Setting up your Project ... "));
87
+ console.log(chalk.whiteBright("\nSetting up project...\n"));
96
88
 
97
- // 1. Create folder structure
98
- const backendFolders = [
99
- 'src/config',
100
- 'src/controllers',
101
- 'src/middlewares',
102
- 'src/models',
103
- 'src/routes',
104
- ];
105
- createFolders(backendFolders);
89
+ // core
90
+ await writeCoreFiles(langchoice);
106
91
 
107
- // 2. Create configuration and code files
92
+ // base module
93
+ await writeUserModule(langchoice);
94
+
95
+ // env
108
96
  await writeEnvFile();
109
- await writeServerFiles();
110
- await writeDbFiles(dbchoice);
111
97
 
112
- // 3. Generate package.json
113
- await createPackageJson(rawProjectName, dbchoice, langchoice);
98
+ // plugins
99
+ const plugins = [];
100
+
101
+ if (dbchoice === 'MongoDB') {
102
+ plugins.push(mongodbPlugin(langchoice));
103
+ }
104
+
105
+ if (dbchoice === 'MySQL') {
106
+ plugins.push(mysqlPlugin(langchoice));
107
+ }
108
+
109
+ if (aiEnabled) {
110
+ plugins.push(aiPlugin(langchoice));
111
+ }
112
+
113
+ await applyPlugins(plugins, { langchoice });
114
+
115
+ // route injection
116
+ const injections = plugins
117
+ .map((p) => p.inject)
118
+ .filter(Boolean);
119
+
120
+ await injectRoutes(langchoice, injections);
121
+
122
+ // package.json
123
+ await createPackageJson(rawProjectName, dbchoice, langchoice, plugins);
114
124
 
115
- // 4. Install dependencies
116
- installer();
125
+ // installer(); // optional
package/installer.js CHANGED
@@ -1,32 +1,30 @@
1
1
  import { createSpinner } from 'nanospinner';
2
2
  import { execSync } from 'child_process';
3
3
  import chalk from 'chalk';
4
- import { exit } from './index.js';
5
4
 
6
- /**
7
- * Installs dependencies using npm install
8
- * Assumes package.json already exists in the current directory
9
- */
10
5
  export function installer() {
11
- const spinner = createSpinner(chalk.whiteBright('Installing Dependencies...')).start();
6
+ const spinner = createSpinner(
7
+ chalk.whiteBright('Installing Dependencies...')
8
+ ).start();
12
9
 
13
10
  try {
14
- // Simple npm install command - reads from package.json
15
11
  execSync('npm install', { stdio: 'inherit' });
16
12
 
17
13
  console.log('\n');
18
14
 
19
- spinner.success({
20
- text: `${chalk.greenBright('Dependencies Installed Successfully!\n')}`
15
+ spinner.success({
16
+ text: chalk.greenBright('Dependencies Installed Successfully!\n')
21
17
  });
22
18
 
23
- exit("Get Started !!!\n");
19
+ console.log(chalk.cyanBright('🚀 Get Started !!!\n'));
24
20
 
21
+ return true;
25
22
  } catch (err) {
26
- spinner.error({
27
- text: `${chalk.redBright('Failed to Install Dependencies')}`
23
+ spinner.error({
24
+ text: chalk.redBright('Failed to Install Dependencies')
28
25
  });
26
+
29
27
  console.error(err);
30
- exit("Try Again !!!");
28
+ return false;
31
29
  }
32
30
  }
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "create-jerry",
3
- "version": "1.0.0",
4
- "description": "A CLI tool to scaffold Express backend projects with MongoDB or MySQL",
3
+ "version": "2.0.0",
4
+ "description": "A CLI to scaffold Express backend projects with MongoDB or MySQL, plugin-based AI modules, and support for JavaScript and TypeScript.",
5
5
  "main": "index.js",
6
6
  "type": "module",
7
7
  "bin": {
8
8
  "create-jerry": "./index.js"
9
9
  },
10
+ "preferGlobal": true,
10
11
  "scripts": {
11
12
  "test": "echo \"Error: no test specified\" && exit 1"
12
13
  },
@@ -44,8 +45,9 @@
44
45
  "index.js",
45
46
  "installer.js",
46
47
  "fileCreator.js",
47
- "folderCreater.js",
48
+ "folderCreator.js",
48
49
  "packageJsonCreator.js",
50
+ "plugins/",
49
51
  "Templates/",
50
52
  "README.md"
51
53
  ]
@@ -1,92 +1,65 @@
1
- import * as fs from 'node:fs/promises';
1
+ import fs from 'fs/promises';
2
2
  import path from 'path';
3
3
 
4
- /**
5
- * Generates package.json file based on project configuration
6
- * @param {string} projectName - Name of the project
7
- * @param {string} dbchoice - Database choice ('MongoDB' or 'MySQL')
8
- * @param {string} langchoice - Language choice ('Typescript' or 'Javascript')
9
- */
10
- export const createPackageJson = async (projectName, dbchoice, langchoice) => {
11
- // Base dependencies that every project needs
12
- const baseDependencies = {
4
+ export const createPackageJson = async (
5
+ name,
6
+ db,
7
+ lang,
8
+ plugins = []
9
+ ) => {
10
+ const isTS = lang.includes('Typescript');
11
+
12
+ const dependencies = {
13
13
  express: '^4.18.2',
14
- dotenv: '^16.3.1',
15
- cors: '^2.8.5'
14
+ cors: '^2.8.5',
15
+ dotenv: '^16.3.1'
16
16
  };
17
17
 
18
- // Database-specific dependencies
19
- const dbDependencies = {
20
- MongoDB: {
21
- mongoose: '^8.0.3'
22
- },
23
- MySQL: {
24
- mysql2: '^3.6.5'
18
+ // safe plugin merge
19
+ for (const plugin of plugins) {
20
+ if (plugin.dependencies) {
21
+ for (const key in plugin.dependencies) {
22
+ if (!dependencies[key]) {
23
+ dependencies[key] = plugin.dependencies[key];
24
+ }
25
+ }
25
26
  }
26
- };
27
-
28
- // Merge base dependencies with database-specific ones
29
- const dependencies = {
30
- ...baseDependencies,
31
- ...dbDependencies[dbchoice]
32
- };
27
+ }
33
28
 
34
- // Development dependencies (common for both JS and TS)
35
29
  const devDependencies = {
36
- nodemon: '^3.0.2'
30
+ nodemon: '^3.0.0'
37
31
  };
38
32
 
39
- // Add TypeScript-specific dev dependencies if needed
40
- if (langchoice.includes('Typescript')) {
41
- devDependencies['typescript'] = '^5.3.3';
42
- devDependencies['@types/node'] = '^20.10.6';
43
- devDependencies['@types/express'] = '^4.17.21';
44
- devDependencies['@types/cors'] = '^2.8.17';
45
- devDependencies['ts-node'] = '^10.9.2';
33
+ if (isTS) {
34
+ devDependencies.typescript = '^5.0.0';
35
+ devDependencies.tsx = '^4.0.0';
36
+ devDependencies['@types/node'] = '^20.0.0';
37
+ devDependencies['@types/express'] = '^4.0.0';
46
38
  }
47
39
 
48
- // Scripts configuration
49
- const scripts = {
50
- start: 'node app.js',
51
- dev: 'nodemon app.js',
52
- test: 'echo "Error: no test specified" && exit 1'
53
- };
54
-
55
- // Modify scripts for TypeScript
56
- if (langchoice.includes('Typescript')) {
57
- scripts.start = 'node dist/app.js';
58
- scripts.dev = 'nodemon --exec ts-node app.ts';
59
- scripts.build = 'tsc';
60
- }
40
+ const scripts = isTS
41
+ ? {
42
+ dev: 'tsx watch src/server.ts',
43
+ build: 'tsc',
44
+ start: 'node dist/server.js'
45
+ }
46
+ : {
47
+ dev: 'nodemon src/server.js',
48
+ start: 'node src/server.js',
49
+ build: 'echo "No build step for JS"'
50
+ };
61
51
 
62
- // Complete package.json object
63
- const packageJson = {
64
- name: projectName.toLowerCase().replace(/\s+/g, '-'),
52
+ const pkg = {
53
+ name,
65
54
  version: '1.0.0',
66
- description: `A ${dbchoice} backend project scaffolded with JerrIt`,
67
- main: langchoice.includes('Typescript') ? 'dist/app.js' : 'app.js',
68
55
  type: 'module',
69
56
  scripts,
70
- keywords: ['express', 'backend', dbchoice.toLowerCase()],
71
- author: '',
72
- license: 'ISC',
73
57
  dependencies,
74
58
  devDependencies
75
59
  };
76
60
 
77
- // Write package.json to the project root
78
- const packageJsonPath = path.join(process.cwd(), 'package.json');
79
-
80
- try {
81
- await fs.writeFile(
82
- packageJsonPath,
83
- JSON.stringify(packageJson, null, 2),
84
- 'utf-8'
85
- );
86
- console.log('✅ package.json created successfully');
87
- return true;
88
- } catch (error) {
89
- console.error('❌ Failed to create package.json:', error);
90
- return false;
91
- }
92
- };
61
+ await fs.writeFile(
62
+ path.join(process.cwd(), 'package.json'),
63
+ JSON.stringify(pkg, null, 2)
64
+ );
65
+ };
@@ -0,0 +1,25 @@
1
+ import { writeAIModule } from '../fileCreator.js';
2
+
3
+ export const aiPlugin = (langchoice) => {
4
+ const isTS = langchoice.includes('Typescript');
5
+
6
+ return {
7
+ name: 'ai',
8
+
9
+ async setup() {
10
+ await writeAIModule(langchoice);
11
+ },
12
+
13
+ inject: {
14
+ import: isTS
15
+ ? "import aiRoutes from '../modules/ai/ai.routes';"
16
+ : "import aiRoutes from '../modules/ai/ai.routes.js';",
17
+
18
+ use: "router.use('/ai', aiRoutes);"
19
+ },
20
+
21
+ dependencies: {
22
+ openai: '^4.0.0'
23
+ }
24
+ };
25
+ };
@@ -0,0 +1,15 @@
1
+ import { writeDbFiles } from '../fileCreator.js';
2
+
3
+ export const mongodbPlugin = (langchoice) => {
4
+ return {
5
+ name: 'mongodb',
6
+
7
+ async setup() {
8
+ await writeDbFiles('MongoDB', langchoice);
9
+ },
10
+
11
+ dependencies: {
12
+ mongoose: '^8.0.0'
13
+ }
14
+ };
15
+ };
@@ -0,0 +1,15 @@
1
+ import { writeDbFiles } from '../fileCreator.js';
2
+
3
+ export const mysqlPlugin = (langchoice) => {
4
+ return {
5
+ name: 'mysql',
6
+
7
+ async setup() {
8
+ await writeDbFiles('MySQL', langchoice);
9
+ },
10
+
11
+ dependencies: {
12
+ mysql2: '^3.0.0'
13
+ }
14
+ };
15
+ };
@@ -0,0 +1,18 @@
1
+ export const applyPlugins = async (plugins = [], context = {}) => {
2
+ for (const plugin of plugins) {
3
+ if (!plugin) continue;
4
+
5
+ try {
6
+ console.log(`⚙️ Applying plugin: ${plugin.name}`);
7
+
8
+ if (plugin.setup) {
9
+ await plugin.setup(context);
10
+ }
11
+
12
+ } catch (err) {
13
+ console.error(`❌ Plugin failed: ${plugin.name}`);
14
+ console.error(err);
15
+ process.exit(1);
16
+ }
17
+ }
18
+ };
@@ -1,20 +0,0 @@
1
- import mongoose from 'mongoose';
2
-
3
- const userSchema = new mongoose.Schema({
4
- username: {
5
- type: String,
6
- required: true,
7
- unique: true,
8
- },
9
- email: {
10
- type: String,
11
- required: true,
12
- unique: true,
13
- },
14
- password: {
15
- type: String,
16
- required: true,
17
- },
18
- }, { timestamps: true });
19
-
20
- export const User = mongoose.model('User', userSchema);
@@ -1,35 +0,0 @@
1
- import mysql from 'mysql2'
2
- import dotenv from 'dotenv'
3
- dotenv.config()
4
-
5
- const pool = mysql.createPool({
6
- host: process.env.MYSQL_HOST ,
7
- user: process.env.MYSQL_USER ,
8
- password: process.env.MYSQL_PASSWORD ,
9
- database: process.env.MYSQL_DATABASE
10
- }).promise()
11
-
12
- export async function getData() {
13
- const [rows] = await pool.query("SELECT * FROM Db")
14
- return rows
15
- }
16
-
17
- export async function getDataById(id) {
18
- const [rows] = await pool.query(`
19
- SELECT * FROM Db
20
- WHERE id = ${id};
21
- `)
22
- return rows[0]
23
- }
24
-
25
- export async function createData(title, contents) {
26
- const [result] = await pool.query(`
27
- INSERT INTO Db (title, contents)
28
- VALUES(?, ?);
29
- `, [title, contents])
30
- const id = result.insertId
31
- return getData(id)
32
- }
33
-
34
- const result = await createData('test', 'test')
35
- console.log(result)
@@ -1,35 +0,0 @@
1
- import express from 'express'
2
- import cors from 'cors'
3
- const app = express()
4
-
5
- app.use(cors())
6
- app.use(json)
7
-
8
-
9
- //get the details
10
- app.get('/view', async (req, res) => {
11
- res.send('hello')
12
- })
13
-
14
- //add new details
15
- app.post('/add', (req, res) => {
16
-
17
- })
18
-
19
- //make changes in the database
20
- app.put('/edit', (req, res) => {
21
-
22
- })
23
-
24
- //delete in the database
25
- app.delete('/delete', (req, res) => {
26
-
27
- })
28
-
29
- app.listen(3000, () => {
30
- try {
31
- console.log(`The server is running on port: ${process.env.PORT}`)
32
- } catch(err) {
33
- console.log(err)
34
- }
35
- })
package/folderCreater.js DELETED
@@ -1,34 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
-
4
- /**
5
- * Creates multiple nested folders inside the project.
6
- * @param {string[]} paths - Relative paths from project root (e.g., ['src/config', 'src/models'])
7
- */
8
-
9
-
10
- export const createProjectDir = (rawProjectName) => {
11
- const projectDir = path.join(process.cwd(), rawProjectName);
12
-
13
- // Create the project folder
14
- if (!fs.existsSync(projectDir)) {
15
- fs.mkdirSync(projectDir);
16
- console.log(`📁 Project root created: ${rawProjectName}`);
17
- }
18
-
19
- // Switch working directory
20
- process.chdir(projectDir);
21
- }
22
-
23
-
24
- export const createFolders = (paths) => {
25
- paths.forEach((folderPath) => {
26
- const fullPath = path.join(process.cwd(), folderPath);
27
- if (!fs.existsSync(fullPath)) {
28
- fs.mkdirSync(fullPath, { recursive: true });
29
- console.log(`📁 Folder created: ${folderPath}`);
30
- } else {
31
- console.log(`📂 Folder already exists: ${folderPath}`);
32
- }
33
- });
34
- };