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
@@ -0,0 +1,72 @@
1
+ import mysql from 'mysql2/promise';
2
+ import dotenv from 'dotenv';
3
+
4
+ dotenv.config();
5
+
6
+ const pool = mysql.createPool({
7
+ host: process.env.MYSQL_HOST,
8
+ user: process.env.MYSQL_USER,
9
+ password: process.env.MYSQL_PASSWORD,
10
+ database: process.env.MYSQL_DATABASE
11
+ });
12
+
13
+ export const connectDB = async (): Promise<void> => {
14
+ try {
15
+ await pool.getConnection();
16
+ console.log('MySQL connected');
17
+ } catch (err) {
18
+ console.error(err);
19
+ process.exit(1);
20
+ }
21
+ };
22
+
23
+ interface User {
24
+ id?: number;
25
+ name: string;
26
+ email: string;
27
+ password: string;
28
+ }
29
+
30
+ // CRUD
31
+
32
+ export const getAllUsers = async (): Promise<User[]> => {
33
+ const [rows] = await pool.query('SELECT * FROM users');
34
+ return rows as User[];
35
+ };
36
+
37
+ export const getUserById = async (
38
+ id: number
39
+ ): Promise<User | undefined> => {
40
+ const [rows] = await pool.query(
41
+ 'SELECT * FROM users WHERE id = ?',
42
+ [id]
43
+ );
44
+ return (rows as User[])[0];
45
+ };
46
+
47
+ export const createUser = async (
48
+ data: User
49
+ ): Promise<User | undefined> => {
50
+ const [result]: any = await pool.query(
51
+ 'INSERT INTO users (name, email, password) VALUES (?, ?, ?)',
52
+ [data.name, data.email, data.password]
53
+ );
54
+
55
+ return getUserById(result.insertId);
56
+ };
57
+
58
+ export const updateUser = async (
59
+ id: number,
60
+ data: Partial<User>
61
+ ): Promise<User | undefined> => {
62
+ await pool.query(
63
+ 'UPDATE users SET name=?, email=?, password=? WHERE id=?',
64
+ [data.name, data.email, data.password, id]
65
+ );
66
+
67
+ return getUserById(id);
68
+ };
69
+
70
+ export const deleteUser = async (id: number): Promise<void> => {
71
+ await pool.query('DELETE FROM users WHERE id=?', [id]);
72
+ };
@@ -0,0 +1,30 @@
1
+ import { askAI } from './ai.service.js';
2
+
3
+ export const handleAIChat = async (req, res) => {
4
+ try {
5
+ const { prompt } = req.body;
6
+
7
+ if (!prompt) {
8
+ return res.status(400).json({
9
+ success: false,
10
+ message: 'Prompt is required'
11
+ });
12
+ }
13
+
14
+ const response = await askAI(prompt);
15
+
16
+ res.status(200).json({
17
+ success: true,
18
+ data: response
19
+ });
20
+
21
+ } catch (error) {
22
+ console.error(error);
23
+
24
+ res.status(500).json({
25
+ success: false,
26
+ message: 'AI request failed',
27
+ error: error.message
28
+ });
29
+ }
30
+ };
@@ -0,0 +1,32 @@
1
+ import OpenAI from 'openai';
2
+
3
+ class AIProvider {
4
+ constructor() {
5
+ this.client = null;
6
+ }
7
+
8
+ init() {
9
+ if (!process.env.OPENAI_API_KEY) {
10
+ throw new Error('OPENAI_API_KEY is missing in .env');
11
+ }
12
+
13
+ this.client = new OpenAI({
14
+ apiKey: process.env.OPENAI_API_KEY
15
+ });
16
+ }
17
+
18
+ async chat(messages) {
19
+ if (!this.client) {
20
+ this.init();
21
+ }
22
+
23
+ const response = await this.client.chat.completions.create({
24
+ model: 'gpt-4o-mini',
25
+ messages
26
+ });
27
+
28
+ return response.choices[0]?.message?.content || '';
29
+ }
30
+ }
31
+
32
+ export default new AIProvider();
@@ -0,0 +1,8 @@
1
+ import express from 'express';
2
+ import { handleAIChat } from './ai.controller.js';
3
+
4
+ const router = express.Router();
5
+
6
+ router.post('/chat', handleAIChat);
7
+
8
+ export default router;
@@ -0,0 +1,16 @@
1
+ import aiProvider from './ai.provider.js';
2
+
3
+ export const askAI = async (userInput) => {
4
+ const messages = [
5
+ {
6
+ role: 'system',
7
+ content: 'You are a helpful backend AI assistant.'
8
+ },
9
+ {
10
+ role: 'user',
11
+ content: userInput
12
+ }
13
+ ];
14
+
15
+ return await aiProvider.chat(messages);
16
+ };
@@ -0,0 +1,31 @@
1
+ import { Request, Response } from 'express';
2
+ import { askAI } from './ai.service.js';
3
+
4
+ export const handleAIChat = async (req: Request, res: Response) => {
5
+ try {
6
+ const { prompt } = req.body;
7
+
8
+ if (!prompt) {
9
+ return res.status(400).json({
10
+ success: false,
11
+ message: 'Prompt is required'
12
+ });
13
+ }
14
+
15
+ const response = await askAI(prompt);
16
+
17
+ res.status(200).json({
18
+ success: true,
19
+ data: response
20
+ });
21
+
22
+ } catch (error: any) {
23
+ console.error(error);
24
+
25
+ res.status(500).json({
26
+ success: false,
27
+ message: 'AI request failed',
28
+ error: error.message
29
+ });
30
+ }
31
+ };
@@ -0,0 +1,30 @@
1
+ import OpenAI from 'openai';
2
+
3
+ class AIProvider {
4
+ private client: OpenAI | null = null;
5
+
6
+ private init() {
7
+ if (!process.env.OPENAI_API_KEY) {
8
+ throw new Error('OPENAI_API_KEY is missing in .env');
9
+ }
10
+
11
+ this.client = new OpenAI({
12
+ apiKey: process.env.OPENAI_API_KEY
13
+ });
14
+ }
15
+
16
+ async chat(messages: OpenAI.Chat.ChatCompletionMessageParam[]) {
17
+ if (!this.client) {
18
+ this.init();
19
+ }
20
+
21
+ const response = await this.client!.chat.completions.create({
22
+ model: 'gpt-4o-mini',
23
+ messages
24
+ });
25
+
26
+ return response.choices[0]?.message?.content || '';
27
+ }
28
+ }
29
+
30
+ export default new AIProvider();
@@ -0,0 +1,8 @@
1
+ import express from 'express';
2
+ import { handleAIChat } from './ai.controller.js';
3
+
4
+ const router = express.Router();
5
+
6
+ router.post('/chat', handleAIChat);
7
+
8
+ export default router;
@@ -0,0 +1,16 @@
1
+ import aiProvider from './ai.provider.js';
2
+
3
+ export const askAI = async (userInput: string): Promise<string> => {
4
+ const messages = [
5
+ {
6
+ role: 'system',
7
+ content: 'You are a helpful backend AI assistant.'
8
+ },
9
+ {
10
+ role: 'user',
11
+ content: userInput
12
+ }
13
+ ];
14
+
15
+ return await aiProvider.chat(messages);
16
+ };
@@ -0,0 +1,46 @@
1
+ import * as userService from './user.service.js';
2
+
3
+ export const getUsers = async (req, res) => {
4
+ try {
5
+ const users = await userService.getUsers();
6
+ res.json({ success: true, data: users });
7
+ } catch (err) {
8
+ res.status(500).json({ success: false, message: err.message });
9
+ }
10
+ };
11
+
12
+ export const getUser = async (req, res) => {
13
+ try {
14
+ const user = await userService.getUserById(req.params.id);
15
+ res.json({ success: true, data: user });
16
+ } catch (err) {
17
+ res.status(500).json({ success: false, message: err.message });
18
+ }
19
+ };
20
+
21
+ export const createUser = async (req, res) => {
22
+ try {
23
+ const user = await userService.createUser(req.body);
24
+ res.status(201).json({ success: true, data: user });
25
+ } catch (err) {
26
+ res.status(500).json({ success: false, message: err.message });
27
+ }
28
+ };
29
+
30
+ export const updateUser = async (req, res) => {
31
+ try {
32
+ const user = await userService.updateUser(req.params.id, req.body);
33
+ res.json({ success: true, data: user });
34
+ } catch (err) {
35
+ res.status(500).json({ success: false, message: err.message });
36
+ }
37
+ };
38
+
39
+ export const deleteUser = async (req, res) => {
40
+ try {
41
+ await userService.deleteUser(req.params.id);
42
+ res.json({ success: true, message: 'User deleted' });
43
+ } catch (err) {
44
+ res.status(500).json({ success: false, message: err.message });
45
+ }
46
+ };
@@ -0,0 +1,25 @@
1
+ import * as db from '../../config/db.js';
2
+
3
+ class UserProvider {
4
+ async getAll() {
5
+ return await db.getAllUsers();
6
+ }
7
+
8
+ async getById(id) {
9
+ return await db.getUserById(id);
10
+ }
11
+
12
+ async create(data) {
13
+ return await db.createUser(data);
14
+ }
15
+
16
+ async update(id, data) {
17
+ return await db.updateUser(id, data);
18
+ }
19
+
20
+ async delete(id) {
21
+ return await db.deleteUser(id);
22
+ }
23
+ }
24
+
25
+ export default new UserProvider();
@@ -0,0 +1,12 @@
1
+ import express from 'express';
2
+ import * as userController from './user.controller.js';
3
+
4
+ const router = express.Router();
5
+
6
+ router.get('/', userController.getUsers);
7
+ router.get('/:id', userController.getUser);
8
+ router.post('/', userController.createUser);
9
+ router.put('/:id', userController.updateUser);
10
+ router.delete('/:id', userController.deleteUser);
11
+
12
+ export default router;
@@ -0,0 +1,21 @@
1
+ import userProvider from './user.provider.js';
2
+
3
+ export const getUsers = async () => {
4
+ return await userProvider.getAll();
5
+ };
6
+
7
+ export const getUserById = async (id) => {
8
+ return await userProvider.getById(id);
9
+ };
10
+
11
+ export const createUser = async (data) => {
12
+ return await userProvider.create(data);
13
+ };
14
+
15
+ export const updateUser = async (id, data) => {
16
+ return await userProvider.update(id, data);
17
+ };
18
+
19
+ export const deleteUser = async (id) => {
20
+ return await userProvider.delete(id);
21
+ };
@@ -0,0 +1,27 @@
1
+ import { Request, Response } from 'express';
2
+ import * as userService from './user.service.js';
3
+
4
+ export const getUsers = async (req: Request, res: Response) => {
5
+ const users = await userService.getUsers();
6
+ res.json({ success: true, data: users });
7
+ };
8
+
9
+ export const getUser = async (req: Request, res: Response) => {
10
+ const user = await userService.getUserById(req.params.id);
11
+ res.json({ success: true, data: user });
12
+ };
13
+
14
+ export const createUser = async (req: Request, res: Response) => {
15
+ const user = await userService.createUser(req.body);
16
+ res.status(201).json({ success: true, data: user });
17
+ };
18
+
19
+ export const updateUser = async (req: Request, res: Response) => {
20
+ const user = await userService.updateUser(req.params.id, req.body);
21
+ res.json({ success: true, data: user });
22
+ };
23
+
24
+ export const deleteUser = async (req: Request, res: Response) => {
25
+ await userService.deleteUser(req.params.id);
26
+ res.json({ success: true });
27
+ };
@@ -0,0 +1,25 @@
1
+ import * as db from '../../config/db.js';
2
+
3
+ class UserProvider {
4
+ async getAll() {
5
+ return await db.getAllUsers();
6
+ }
7
+
8
+ async getById(id: string) {
9
+ return await db.getUserById(id);
10
+ }
11
+
12
+ async create(data: any) {
13
+ return await db.createUser(data);
14
+ }
15
+
16
+ async update(id: string, data: any) {
17
+ return await db.updateUser(id, data);
18
+ }
19
+
20
+ async delete(id: string) {
21
+ return await db.deleteUser(id);
22
+ }
23
+ }
24
+
25
+ export default new UserProvider();
@@ -0,0 +1,12 @@
1
+ import express from 'express';
2
+ import * as userController from './user.controller.js';
3
+
4
+ const router = express.Router();
5
+
6
+ router.get('/', userController.getUsers);
7
+ router.get('/:id', userController.getUser);
8
+ router.post('/', userController.createUser);
9
+ router.put('/:id', userController.updateUser);
10
+ router.delete('/:id', userController.deleteUser);
11
+
12
+ export default router;
@@ -0,0 +1,21 @@
1
+ import userProvider from './user.provider.js';
2
+
3
+ export const getUsers = async () => {
4
+ return await userProvider.getAll();
5
+ };
6
+
7
+ export const getUserById = async (id: string) => {
8
+ return await userProvider.getById(id);
9
+ };
10
+
11
+ export const createUser = async (data: any) => {
12
+ return await userProvider.create(data);
13
+ };
14
+
15
+ export const updateUser = async (id: string, data: any) => {
16
+ return await userProvider.update(id, data);
17
+ };
18
+
19
+ export const deleteUser = async (id: string) => {
20
+ return await userProvider.delete(id);
21
+ };
package/fileCreator.js CHANGED
@@ -1,49 +1,158 @@
1
- import { fileURLToPath } from 'url';
2
1
  import path from 'path';
3
- import * as fs from 'node:fs/promises';
2
+ import * as fs from 'fs/promises';
3
+ import { existsSync } from 'fs';
4
+ import { fileURLToPath } from 'url';
4
5
 
5
6
  const __filename = fileURLToPath(import.meta.url);
6
7
  const __dirname = path.dirname(__filename);
7
8
 
8
- // Stable reference to your Templates folder in scaff/
9
9
  const templateDir = path.join(__dirname, 'Templates');
10
10
 
11
- // 🟡 Create empty .env
12
- export const writeEnvFile = async () => {
13
- const envPath = path.join(process.cwd(), 'src', 'config', '.env');
11
+ if (!existsSync(templateDir)) {
12
+ throw new Error(`Templates folder missing at ${templateDir}`);
13
+ }
14
+
15
+ // ---------------- HELPERS ----------------
16
+
17
+ const copyFile = async (src, dest) => {
18
+ const content = await fs.readFile(src);
19
+ await fs.mkdir(path.dirname(dest), { recursive: true });
20
+ await fs.writeFile(dest, content);
21
+ };
22
+
23
+ const copyDir = async (srcDir, destDir) => {
14
24
  try {
15
- await fs.writeFile(envPath, '', 'utf-8');
16
- console.log('✅ .env file created in src/config');
17
- } catch (error) {
18
- console.error('❌ Failed to create .env file:', error);
25
+ const entries = await fs.readdir(srcDir, { withFileTypes: true });
26
+
27
+ for (const entry of entries) {
28
+ const src = path.join(srcDir, entry.name);
29
+ const dest = path.join(destDir, entry.name);
30
+
31
+ if (entry.isDirectory()) {
32
+ await copyDir(src, dest);
33
+ } else {
34
+ await copyFile(src, dest);
35
+ }
36
+ }
37
+ } catch {
38
+ throw new Error(`Template missing or invalid: ${srcDir}`);
19
39
  }
20
40
  };
21
41
 
22
- // 🔵 Generate db.js from template
23
- export const writeDbFiles = async (dbchoice) => {
24
- const dbfile = dbchoice === 'MySQL' ? 'db-sql.js' : 'db-mongo.js';
25
- const dbTemplatePath = path.join(templateDir, dbfile);
26
- const targetPath = path.join(process.cwd(), 'src', 'models', 'db.js');
42
+ // ---------------- CORE ----------------
27
43
 
28
- try {
29
- const content = await fs.readFile(dbTemplatePath, 'utf-8');
30
- await fs.writeFile(targetPath, content);
31
- console.log(' db.js created successfully');
32
- } catch (error) {
33
- console.error('❌ Failed to create db.js:', error);
44
+ export const writeCoreFiles = async (langchoice) => {
45
+ const variant = langchoice.includes('Typescript') ? 'ts' : 'js';
46
+
47
+ const basePath = path.join(templateDir, 'base', variant);
48
+
49
+ // copy base project directly into src
50
+ await copyDir(
51
+ basePath,
52
+ path.join(process.cwd(), 'src')
53
+ );
54
+
55
+ // tsconfig (only TS)
56
+ if (variant === 'ts') {
57
+ const tsconfigPath = path.join(basePath, 'tsconfig.json');
58
+
59
+ if (existsSync(tsconfigPath)) {
60
+ await copyFile(
61
+ tsconfigPath,
62
+ path.join(process.cwd(), 'tsconfig.json')
63
+ );
64
+ }
34
65
  }
35
66
  };
36
67
 
37
- // 🟢 Generate app.js from express.js
38
- export const writeServerFiles = async () => {
39
- const serverTemplatePath = path.join(templateDir, 'express.js');
40
- const targetPath = path.join(process.cwd(), 'app.js');
68
+ // ---------------- USER MODULE ----------------
69
+
70
+ export const writeUserModule = async (langchoice) => {
71
+ const variant = langchoice.includes('Typescript') ? 'ts' : 'js';
72
+
73
+ const src = path.join(templateDir, 'modules/user', variant);
74
+ const dest = path.join(process.cwd(), 'src/modules/user');
75
+
76
+ await copyDir(src, dest);
77
+ };
78
+
79
+ // ---------------- AI MODULE ----------------
80
+
81
+ export const writeAIModule = async (langchoice) => {
82
+ const variant = langchoice.includes('Typescript') ? 'ts' : 'js';
83
+
84
+ const src = path.join(templateDir, 'modules/ai', variant);
85
+ const dest = path.join(process.cwd(), 'src/modules/ai');
86
+
87
+ await copyDir(src, dest);
88
+ };
89
+
90
+ // ---------------- DB (LEGACY SAFE) ----------------
91
+
92
+ export const writeDbFiles = async (dbchoice, langchoice) => {
93
+ const variant = langchoice.includes('Typescript') ? 'ts' : 'js';
94
+ const db = dbchoice === 'MongoDB' ? 'mongodb' : 'mysql';
95
+
96
+ await copyDir(
97
+ path.join(templateDir, 'db', db, variant),
98
+ path.join(process.cwd(), 'src/config')
99
+ );
100
+ };
101
+
102
+ // ---------------- ENV ----------------
103
+
104
+ export const writeEnvFile = async () => {
105
+ const content = `PORT=3000
106
+
107
+ # MongoDB
108
+ MONGO_URI=
109
+
110
+ # MySQL
111
+ MYSQL_HOST=
112
+ MYSQL_USER=
113
+ MYSQL_PASSWORD=
114
+ MYSQL_DATABASE=
115
+
116
+ # AI
117
+ OPENAI_API_KEY=
118
+ `;
119
+
120
+ await fs.writeFile(path.join(process.cwd(), '.env'), content);
121
+ };
122
+
123
+ // ---------------- ROUTE INJECTION ----------------
124
+
125
+ export const injectRoutes = async (langchoice, injections = []) => {
126
+ const ext = langchoice.includes('Typescript') ? 'ts' : 'js';
127
+
128
+ const filePath = path.join(process.cwd(), `src/routes/index.${ext}`);
41
129
 
42
130
  try {
43
- const content = await fs.readFile(serverTemplatePath, 'utf-8');
44
- await fs.writeFile(targetPath, content);
45
- console.log('✅ app.js created successfully');
46
- } catch (error) {
47
- console.error('❌ Failed to create app.js:', error);
131
+ await fs.stat(filePath);
132
+ } catch {
133
+ throw new Error(`Routes file not found: ${filePath}`);
48
134
  }
49
- };
135
+
136
+ let content = await fs.readFile(filePath, 'utf-8');
137
+
138
+ if (
139
+ !content.includes('// [IMPORT_ROUTES]') ||
140
+ !content.includes('// [USE_ROUTES]')
141
+ ) {
142
+ throw new Error('Route placeholders missing in base template');
143
+ }
144
+
145
+ for (const inject of injections) {
146
+ content = content.replace(
147
+ '// [IMPORT_ROUTES]',
148
+ `${inject.import}\n// [IMPORT_ROUTES]`
149
+ );
150
+
151
+ content = content.replace(
152
+ '// [USE_ROUTES]',
153
+ `${inject.use}\n// [USE_ROUTES]`
154
+ );
155
+ }
156
+
157
+ await fs.writeFile(filePath, content);
158
+ };
@@ -0,0 +1,15 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+
4
+ export const createProjectDir = (rawProjectName) => {
5
+ const projectDir = path.join(process.cwd(), rawProjectName);
6
+
7
+ if (fs.existsSync(projectDir)) {
8
+ throw new Error(`Folder "${rawProjectName}" already exists`);
9
+ }
10
+
11
+ fs.mkdirSync(projectDir);
12
+ console.log(`📁 Project root created: ${rawProjectName}`);
13
+
14
+ process.chdir(projectDir);
15
+ };