katax-cli 0.1.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.
- package/README.md +0 -0
- package/dist/commands/add-endpoint.d.ts +6 -0
- package/dist/commands/add-endpoint.js +229 -0
- package/dist/commands/generate-crud.d.ts +5 -0
- package/dist/commands/generate-crud.js +282 -0
- package/dist/commands/info.d.ts +1 -0
- package/dist/commands/info.js +80 -0
- package/dist/commands/init.d.ts +5 -0
- package/dist/commands/init.js +1315 -0
- package/dist/database/mongodb.ts +46 -0
- package/dist/database/mysql.ts +26 -0
- package/dist/database/postgresql.ts +52 -0
- package/dist/generators/controller-generator.d.ts +2 -0
- package/dist/generators/controller-generator.js +223 -0
- package/dist/generators/handler-generator.d.ts +2 -0
- package/dist/generators/handler-generator.js +84 -0
- package/dist/generators/route-generator.d.ts +2 -0
- package/dist/generators/route-generator.js +50 -0
- package/dist/generators/router-updater.d.ts +2 -0
- package/dist/generators/router-updater.js +48 -0
- package/dist/generators/validator-generator.d.ts +2 -0
- package/dist/generators/validator-generator.js +160 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +101 -0
- package/dist/types/index.d.ts +50 -0
- package/dist/types/index.js +1 -0
- package/dist/utils/file-utils.d.ts +40 -0
- package/dist/utils/file-utils.js +89 -0
- package/dist/utils/logger.d.ts +10 -0
- package/dist/utils/logger.js +38 -0
- package/package.json +68 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { MongoClient, Db } from 'mongodb';
|
|
2
|
+
|
|
3
|
+
let client: MongoClient;
|
|
4
|
+
let db: Db;
|
|
5
|
+
|
|
6
|
+
export async function connect(): Promise<Db> {
|
|
7
|
+
if (db) {
|
|
8
|
+
return db;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const uri = process.env.DATABASE_URL;
|
|
12
|
+
if (!uri) {
|
|
13
|
+
throw new Error('DATABASE_URL is not defined in environment variables');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
client = new MongoClient(uri);
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
await client.connect();
|
|
20
|
+
console.log('✅ Connected to MongoDB database');
|
|
21
|
+
|
|
22
|
+
const dbName = uri.split('/').pop()?.split('?')[0];
|
|
23
|
+
db = client.db(dbName);
|
|
24
|
+
|
|
25
|
+
return db;
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error('❌ MongoDB connection error:', error);
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function disconnect(): Promise<void> {
|
|
33
|
+
if (client) {
|
|
34
|
+
await client.close();
|
|
35
|
+
console.log('Disconnected from MongoDB');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getDb(): Db {
|
|
40
|
+
if (!db) {
|
|
41
|
+
throw new Error('Database not initialized. Call connect() first.');
|
|
42
|
+
}
|
|
43
|
+
return db;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default { connect, disconnect, getDb };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import mysql from 'mysql2/promise';
|
|
2
|
+
|
|
3
|
+
const pool = mysql.createPool({
|
|
4
|
+
uri: process.env.DATABASE_URL,
|
|
5
|
+
waitForConnections: true,
|
|
6
|
+
connectionLimit: 10,
|
|
7
|
+
queueLimit: 0
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
pool.on('connection', () => {
|
|
11
|
+
console.log('✅ Connected to MySQL database');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export default pool;
|
|
15
|
+
|
|
16
|
+
export async function query(sql: string, params?: any[]) {
|
|
17
|
+
const start = Date.now();
|
|
18
|
+
const [rows] = await pool.execute(sql, params);
|
|
19
|
+
const duration = Date.now() - start;
|
|
20
|
+
console.log('Executed query', { sql, duration, rows: Array.isArray(rows) ? rows.length : 0 });
|
|
21
|
+
return rows;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function getConnection() {
|
|
25
|
+
return await pool.getConnection();
|
|
26
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Pool } from 'pg';
|
|
2
|
+
|
|
3
|
+
const pool = new Pool({
|
|
4
|
+
connectionString: process.env.DATABASE_URL,
|
|
5
|
+
ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
pool.on('connect', () => {
|
|
9
|
+
console.log('✅ Connected to PostgreSQL database');
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
pool.on('error', (err) => {
|
|
13
|
+
console.error('❌ PostgreSQL connection error:', err);
|
|
14
|
+
process.exit(-1);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export default pool;
|
|
18
|
+
|
|
19
|
+
export async function query(text: string, params?: any[]) {
|
|
20
|
+
const start = Date.now();
|
|
21
|
+
const res = await pool.query(text, params);
|
|
22
|
+
const duration = Date.now() - start;
|
|
23
|
+
console.log('Executed query', { text, duration, rows: res.rowCount });
|
|
24
|
+
return res;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function getClient() {
|
|
28
|
+
const client = await pool.connect();
|
|
29
|
+
const query = client.query;
|
|
30
|
+
const release = client.release;
|
|
31
|
+
|
|
32
|
+
// Set a timeout of 5 seconds, after which we will log this client's last query
|
|
33
|
+
const timeout = setTimeout(() => {
|
|
34
|
+
console.error('A client has been checked out for more than 5 seconds!');
|
|
35
|
+
console.error(`The last executed query on this client was: ${(client as any).lastQuery}`);
|
|
36
|
+
}, 5000);
|
|
37
|
+
|
|
38
|
+
// Monkey patch the query method to keep track of the last query executed
|
|
39
|
+
client.query = (...args: any[]) => {
|
|
40
|
+
(client as any).lastQuery = args;
|
|
41
|
+
return query.apply(client, args);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
client.release = () => {
|
|
45
|
+
clearTimeout(timeout);
|
|
46
|
+
client.query = query;
|
|
47
|
+
client.release = release;
|
|
48
|
+
return release.apply(client);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
return client;
|
|
52
|
+
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { toPascalCase, toCamelCase } from '../utils/file-utils.js';
|
|
2
|
+
export function generateController(config) {
|
|
3
|
+
const { name, method, fields = [] } = config;
|
|
4
|
+
const pascalName = toPascalCase(name);
|
|
5
|
+
const camelName = toCamelCase(name);
|
|
6
|
+
let content = '';
|
|
7
|
+
// Imports
|
|
8
|
+
if (config.addValidation) {
|
|
9
|
+
content += `import { ${pascalName}Data } from './${name.toLowerCase()}.validator.js';\n`;
|
|
10
|
+
}
|
|
11
|
+
content += `import {\n`;
|
|
12
|
+
content += ` ControllerResult,\n`;
|
|
13
|
+
content += ` createSuccessResult,\n`;
|
|
14
|
+
content += ` createErrorResult\n`;
|
|
15
|
+
content += `} from '../../shared/api.utils.js';\n`;
|
|
16
|
+
content += `// import pool from '../../database/db.config.js'; // Uncomment if using database\n\n`;
|
|
17
|
+
// Generate controller function based on method
|
|
18
|
+
switch (method) {
|
|
19
|
+
case 'POST':
|
|
20
|
+
content += generateCreateController(pascalName, camelName, fields);
|
|
21
|
+
break;
|
|
22
|
+
case 'GET':
|
|
23
|
+
content += generateGetController(pascalName, camelName);
|
|
24
|
+
break;
|
|
25
|
+
case 'PUT':
|
|
26
|
+
case 'PATCH':
|
|
27
|
+
content += generateUpdateController(pascalName, camelName, fields);
|
|
28
|
+
break;
|
|
29
|
+
case 'DELETE':
|
|
30
|
+
content += generateDeleteController(pascalName, camelName);
|
|
31
|
+
break;
|
|
32
|
+
default:
|
|
33
|
+
content += generateGenericController(pascalName, camelName, method);
|
|
34
|
+
}
|
|
35
|
+
return content;
|
|
36
|
+
}
|
|
37
|
+
function generateCreateController(pascalName, camelName, fields) {
|
|
38
|
+
return `/**
|
|
39
|
+
* Create a new ${camelName}
|
|
40
|
+
*/
|
|
41
|
+
export async function create${pascalName}(
|
|
42
|
+
data: ${pascalName}Data
|
|
43
|
+
): Promise<ControllerResult<any>> {
|
|
44
|
+
try {
|
|
45
|
+
console.log(\`[${pascalName.toUpperCase()}] Creating ${camelName}:\`, data);
|
|
46
|
+
|
|
47
|
+
// TODO: Implement database insertion
|
|
48
|
+
// const result = await pool.query(
|
|
49
|
+
// 'INSERT INTO ${camelName}s (${fields.map(f => f.name).join(', ')}) VALUES (${fields.map((_, i) => `$${i + 1}`).join(', ')}) RETURNING *',
|
|
50
|
+
// [${fields.map(f => `data.${f.name}`).join(', ')}]
|
|
51
|
+
// );
|
|
52
|
+
// const new${pascalName} = result.rows[0];
|
|
53
|
+
|
|
54
|
+
// Mock response for now
|
|
55
|
+
const new${pascalName} = {
|
|
56
|
+
id: Math.floor(Math.random() * 1000),
|
|
57
|
+
...data,
|
|
58
|
+
createdAt: new Date().toISOString()
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return createSuccessResult(
|
|
62
|
+
'${pascalName} created successfully',
|
|
63
|
+
new${pascalName},
|
|
64
|
+
undefined,
|
|
65
|
+
201
|
|
66
|
+
);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error(\`[${pascalName.toUpperCase()}] Error creating ${camelName}:\`, error);
|
|
69
|
+
return createErrorResult(
|
|
70
|
+
'Failed to create ${camelName}',
|
|
71
|
+
error instanceof Error ? error.message : 'Unknown error',
|
|
72
|
+
500
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
`;
|
|
77
|
+
}
|
|
78
|
+
function generateGetController(pascalName, camelName) {
|
|
79
|
+
return `/**
|
|
80
|
+
* Get ${camelName}(s)
|
|
81
|
+
*/
|
|
82
|
+
export async function get${pascalName}(
|
|
83
|
+
id?: string
|
|
84
|
+
): Promise<ControllerResult<any>> {
|
|
85
|
+
try {
|
|
86
|
+
console.log(\`[${pascalName.toUpperCase()}] Getting ${camelName}\`, id ? \`with id: \${id}\` : '(all)');
|
|
87
|
+
|
|
88
|
+
// TODO: Implement database query
|
|
89
|
+
// if (id) {
|
|
90
|
+
// const result = await pool.query('SELECT * FROM ${camelName}s WHERE id = $1', [id]);
|
|
91
|
+
// if (result.rows.length === 0) {
|
|
92
|
+
// return createErrorResult('${pascalName} not found', undefined, 404);
|
|
93
|
+
// }
|
|
94
|
+
// return createSuccessResult('${pascalName} retrieved', result.rows[0]);
|
|
95
|
+
// } else {
|
|
96
|
+
// const result = await pool.query('SELECT * FROM ${camelName}s');
|
|
97
|
+
// return createSuccessResult('${pascalName}s retrieved', result.rows);
|
|
98
|
+
// }
|
|
99
|
+
|
|
100
|
+
// Mock response for now
|
|
101
|
+
const mock${pascalName} = {
|
|
102
|
+
id: id || 1,
|
|
103
|
+
name: 'Sample ${pascalName}',
|
|
104
|
+
createdAt: new Date().toISOString()
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
return createSuccessResult(
|
|
108
|
+
'${pascalName} retrieved successfully',
|
|
109
|
+
id ? mock${pascalName} : [mock${pascalName}]
|
|
110
|
+
);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.error(\`[${pascalName.toUpperCase()}] Error getting ${camelName}:\`, error);
|
|
113
|
+
return createErrorResult(
|
|
114
|
+
'Failed to get ${camelName}',
|
|
115
|
+
error instanceof Error ? error.message : 'Unknown error',
|
|
116
|
+
500
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
`;
|
|
121
|
+
}
|
|
122
|
+
function generateUpdateController(pascalName, camelName, fields) {
|
|
123
|
+
return `/**
|
|
124
|
+
* Update ${camelName}
|
|
125
|
+
*/
|
|
126
|
+
export async function update${pascalName}(
|
|
127
|
+
id: string,
|
|
128
|
+
data: Partial<${pascalName}Data>
|
|
129
|
+
): Promise<ControllerResult<any>> {
|
|
130
|
+
try {
|
|
131
|
+
console.log(\`[${pascalName.toUpperCase()}] Updating ${camelName} \${id}:\`, data);
|
|
132
|
+
|
|
133
|
+
// TODO: Implement database update
|
|
134
|
+
// const result = await pool.query(
|
|
135
|
+
// 'UPDATE ${camelName}s SET ... WHERE id = $1 RETURNING *',
|
|
136
|
+
// [id, ...]
|
|
137
|
+
// );
|
|
138
|
+
// if (result.rows.length === 0) {
|
|
139
|
+
// return createErrorResult('${pascalName} not found', undefined, 404);
|
|
140
|
+
// }
|
|
141
|
+
|
|
142
|
+
// Mock response for now
|
|
143
|
+
const updated${pascalName} = {
|
|
144
|
+
id: parseInt(id),
|
|
145
|
+
...data,
|
|
146
|
+
updatedAt: new Date().toISOString()
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
return createSuccessResult(
|
|
150
|
+
'${pascalName} updated successfully',
|
|
151
|
+
updated${pascalName}
|
|
152
|
+
);
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.error(\`[${pascalName.toUpperCase()}] Error updating ${camelName}:\`, error);
|
|
155
|
+
return createErrorResult(
|
|
156
|
+
'Failed to update ${camelName}',
|
|
157
|
+
error instanceof Error ? error.message : 'Unknown error',
|
|
158
|
+
500
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
`;
|
|
163
|
+
}
|
|
164
|
+
function generateDeleteController(pascalName, camelName) {
|
|
165
|
+
return `/**
|
|
166
|
+
* Delete ${camelName}
|
|
167
|
+
*/
|
|
168
|
+
export async function delete${pascalName}(
|
|
169
|
+
id: string
|
|
170
|
+
): Promise<ControllerResult<void>> {
|
|
171
|
+
try {
|
|
172
|
+
console.log(\`[${pascalName.toUpperCase()}] Deleting ${camelName} \${id}\`);
|
|
173
|
+
|
|
174
|
+
// TODO: Implement database deletion
|
|
175
|
+
// const result = await pool.query('DELETE FROM ${camelName}s WHERE id = $1 RETURNING id', [id]);
|
|
176
|
+
// if (result.rows.length === 0) {
|
|
177
|
+
// return createErrorResult('${pascalName} not found', undefined, 404);
|
|
178
|
+
// }
|
|
179
|
+
|
|
180
|
+
return createSuccessResult(
|
|
181
|
+
'${pascalName} deleted successfully',
|
|
182
|
+
undefined,
|
|
183
|
+
undefined,
|
|
184
|
+
200
|
|
185
|
+
);
|
|
186
|
+
} catch (error) {
|
|
187
|
+
console.error(\`[${pascalName.toUpperCase()}] Error deleting ${camelName}:\`, error);
|
|
188
|
+
return createErrorResult(
|
|
189
|
+
'Failed to delete ${camelName}',
|
|
190
|
+
error instanceof Error ? error.message : 'Unknown error',
|
|
191
|
+
500
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
`;
|
|
196
|
+
}
|
|
197
|
+
function generateGenericController(pascalName, camelName, method) {
|
|
198
|
+
return `/**
|
|
199
|
+
* Handle ${method} request for ${camelName}
|
|
200
|
+
*/
|
|
201
|
+
export async function handle${pascalName}${method}(
|
|
202
|
+
data?: any
|
|
203
|
+
): Promise<ControllerResult<any>> {
|
|
204
|
+
try {
|
|
205
|
+
console.log(\`[${pascalName.toUpperCase()}] Handling ${method} request\`, data);
|
|
206
|
+
|
|
207
|
+
// TODO: Implement your logic here
|
|
208
|
+
|
|
209
|
+
return createSuccessResult(
|
|
210
|
+
'Request processed successfully',
|
|
211
|
+
{ message: '${method} ${camelName} endpoint' }
|
|
212
|
+
);
|
|
213
|
+
} catch (error) {
|
|
214
|
+
console.error(\`[${pascalName.toUpperCase()}] Error:\`, error);
|
|
215
|
+
return createErrorResult(
|
|
216
|
+
'Failed to process request',
|
|
217
|
+
error instanceof Error ? error.message : 'Unknown error',
|
|
218
|
+
500
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
`;
|
|
223
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { toPascalCase, toCamelCase } from '../utils/file-utils.js';
|
|
2
|
+
export function generateHandler(config) {
|
|
3
|
+
const { name, method } = config;
|
|
4
|
+
const pascalName = toPascalCase(name);
|
|
5
|
+
const camelName = toCamelCase(name);
|
|
6
|
+
let content = "import { Request, Response } from 'express';\n";
|
|
7
|
+
if (config.addValidation) {
|
|
8
|
+
content += `import { validate${pascalName} } from './${name.toLowerCase()}.validator.js';\n`;
|
|
9
|
+
}
|
|
10
|
+
// Import controller functions
|
|
11
|
+
switch (method) {
|
|
12
|
+
case 'POST':
|
|
13
|
+
content += `import { create${pascalName} } from './${name.toLowerCase()}.controller.js';\n`;
|
|
14
|
+
break;
|
|
15
|
+
case 'GET':
|
|
16
|
+
content += `import { get${pascalName} } from './${name.toLowerCase()}.controller.js';\n`;
|
|
17
|
+
break;
|
|
18
|
+
case 'PUT':
|
|
19
|
+
case 'PATCH':
|
|
20
|
+
content += `import { update${pascalName} } from './${name.toLowerCase()}.controller.js';\n`;
|
|
21
|
+
break;
|
|
22
|
+
case 'DELETE':
|
|
23
|
+
content += `import { delete${pascalName} } from './${name.toLowerCase()}.controller.js';\n`;
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
content += "import { sendResponse } from '../../shared/api.utils.js';\n\n";
|
|
27
|
+
content += "// ==================== HANDLERS ====================\n\n";
|
|
28
|
+
// Generate handler based on method
|
|
29
|
+
content += generateHandlerFunction(method, pascalName, camelName, config.addValidation);
|
|
30
|
+
return content;
|
|
31
|
+
}
|
|
32
|
+
function generateHandlerFunction(method, pascalName, camelName, hasValidation) {
|
|
33
|
+
const handlerName = getHandlerName(method, pascalName);
|
|
34
|
+
let content = `/**\n * Handler for ${method} ${camelName}\n`;
|
|
35
|
+
content += ` * Uses sendResponse utility for automatic validation and response handling\n */\n`;
|
|
36
|
+
content += `export async function ${handlerName}(req: Request, res: Response): Promise<void> {\n`;
|
|
37
|
+
content += ` await sendResponse(\n`;
|
|
38
|
+
content += ` req,\n`;
|
|
39
|
+
content += ` res,\n`;
|
|
40
|
+
// Validator based on method
|
|
41
|
+
if (hasValidation && (method === 'POST' || method === 'PUT' || method === 'PATCH')) {
|
|
42
|
+
content += ` () => validate${pascalName}(req.body),\n`;
|
|
43
|
+
}
|
|
44
|
+
else if (method === 'GET' || method === 'DELETE') {
|
|
45
|
+
content += ` () => validate${pascalName}Id(req.params.id),\n`;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
content += ` () => validate${pascalName}(req.body),\n`;
|
|
49
|
+
}
|
|
50
|
+
// Controller call based on method
|
|
51
|
+
switch (method) {
|
|
52
|
+
case 'POST':
|
|
53
|
+
content += ` (validData) => create${pascalName}(validData)\n`;
|
|
54
|
+
break;
|
|
55
|
+
case 'GET':
|
|
56
|
+
content += ` (validData) => get${pascalName}(validData)\n`;
|
|
57
|
+
break;
|
|
58
|
+
case 'PUT':
|
|
59
|
+
case 'PATCH':
|
|
60
|
+
content += ` (validData) => update${pascalName}(req.params.id, validData)\n`;
|
|
61
|
+
break;
|
|
62
|
+
case 'DELETE':
|
|
63
|
+
content += ` (validData) => delete${pascalName}(validData)\n`;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
content += ` );\n`;
|
|
67
|
+
content += `}\n`;
|
|
68
|
+
return content;
|
|
69
|
+
}
|
|
70
|
+
function getHandlerName(method, pascalName) {
|
|
71
|
+
switch (method) {
|
|
72
|
+
case 'POST':
|
|
73
|
+
return `create${pascalName}Handler`;
|
|
74
|
+
case 'GET':
|
|
75
|
+
return `get${pascalName}Handler`;
|
|
76
|
+
case 'PUT':
|
|
77
|
+
case 'PATCH':
|
|
78
|
+
return `update${pascalName}Handler`;
|
|
79
|
+
case 'DELETE':
|
|
80
|
+
return `delete${pascalName}Handler`;
|
|
81
|
+
default:
|
|
82
|
+
return `handle${pascalName}${method}`;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { toPascalCase } from '../utils/file-utils.js';
|
|
2
|
+
export function generateRoute(config) {
|
|
3
|
+
const { name, method, path } = config;
|
|
4
|
+
const pascalName = toPascalCase(name);
|
|
5
|
+
let content = "import { Router } from 'express';\n";
|
|
6
|
+
// Import handler function
|
|
7
|
+
const handlerName = getHandlerName(method, pascalName);
|
|
8
|
+
content += `import { ${handlerName} } from './${name.toLowerCase()}.handler.js';\n\n`;
|
|
9
|
+
content += `const router = Router();\n\n`;
|
|
10
|
+
content += `// ==================== ROUTES ====================\n\n`;
|
|
11
|
+
// Generate route
|
|
12
|
+
const routePath = path.replace(/^\/api/, '');
|
|
13
|
+
content += `/**\n`;
|
|
14
|
+
content += ` * @route ${method} ${path}\n`;
|
|
15
|
+
content += ` * @desc ${getRouteDescription(method, pascalName)}\n`;
|
|
16
|
+
content += ` */\n`;
|
|
17
|
+
content += `router.${method.toLowerCase()}('${routePath}', ${handlerName});\n\n`;
|
|
18
|
+
content += `export default router;\n`;
|
|
19
|
+
return content;
|
|
20
|
+
}
|
|
21
|
+
function getHandlerName(method, pascalName) {
|
|
22
|
+
switch (method) {
|
|
23
|
+
case 'POST':
|
|
24
|
+
return `create${pascalName}Handler`;
|
|
25
|
+
case 'GET':
|
|
26
|
+
return `get${pascalName}Handler`;
|
|
27
|
+
case 'PUT':
|
|
28
|
+
case 'PATCH':
|
|
29
|
+
return `update${pascalName}Handler`;
|
|
30
|
+
case 'DELETE':
|
|
31
|
+
return `delete${pascalName}Handler`;
|
|
32
|
+
default:
|
|
33
|
+
return `handle${pascalName}${method}`;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function getRouteDescription(method, name) {
|
|
37
|
+
switch (method) {
|
|
38
|
+
case 'POST':
|
|
39
|
+
return `Create a new ${name}`;
|
|
40
|
+
case 'GET':
|
|
41
|
+
return `Get ${name}(s)`;
|
|
42
|
+
case 'PUT':
|
|
43
|
+
case 'PATCH':
|
|
44
|
+
return `Update ${name}`;
|
|
45
|
+
case 'DELETE':
|
|
46
|
+
return `Delete ${name}`;
|
|
47
|
+
default:
|
|
48
|
+
return `Handle ${method} request for ${name}`;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { fileExists, writeFile } from '../utils/file-utils.js';
|
|
3
|
+
export async function updateMainRouter(name, config) {
|
|
4
|
+
const routesPath = path.join(process.cwd(), 'src', 'api', 'routes.ts');
|
|
5
|
+
let content;
|
|
6
|
+
if (fileExists(routesPath)) {
|
|
7
|
+
// Read existing routes.ts
|
|
8
|
+
const fs = await import('fs');
|
|
9
|
+
content = await fs.promises.readFile(routesPath, 'utf-8');
|
|
10
|
+
// Check if import already exists
|
|
11
|
+
const importStatement = `import ${name.toLowerCase()}Router from './${name.toLowerCase()}/${name.toLowerCase()}.routes.js';`;
|
|
12
|
+
if (!content.includes(importStatement)) {
|
|
13
|
+
// Add import after last import
|
|
14
|
+
const lastImportIndex = content.lastIndexOf('import ');
|
|
15
|
+
const endOfLineIndex = content.indexOf('\n', lastImportIndex);
|
|
16
|
+
content = content.slice(0, endOfLineIndex + 1) + importStatement + '\n' + content.slice(endOfLineIndex + 1);
|
|
17
|
+
}
|
|
18
|
+
// Add route registration
|
|
19
|
+
const routePath = config.path.replace(/^\/api/, '');
|
|
20
|
+
const basePath = routePath.split('/')[1] || name.toLowerCase();
|
|
21
|
+
const routeStatement = `router.use('/${basePath}', ${name.toLowerCase()}Router);`;
|
|
22
|
+
if (!content.includes(routeStatement)) {
|
|
23
|
+
// Add before export default
|
|
24
|
+
const exportIndex = content.lastIndexOf('export default router;');
|
|
25
|
+
if (exportIndex !== -1) {
|
|
26
|
+
content = content.slice(0, exportIndex) + routeStatement + '\n\n' + content.slice(exportIndex);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
content += `\n${routeStatement}\n`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
// Create new routes.ts
|
|
35
|
+
content = `import { Router } from 'express';\n`;
|
|
36
|
+
content += `import ${name.toLowerCase()}Router from './${name.toLowerCase()}/${name.toLowerCase()}.routes.js';\n\n`;
|
|
37
|
+
content += `const router = Router();\n\n`;
|
|
38
|
+
content += `// Health check\n`;
|
|
39
|
+
content += `router.get('/health', (req, res) => {\n`;
|
|
40
|
+
content += ` res.json({ status: 'ok', timestamp: new Date().toISOString() });\n`;
|
|
41
|
+
content += `});\n\n`;
|
|
42
|
+
const routePath = config.path.replace(/^\/api/, '');
|
|
43
|
+
const basePath = routePath.split('/')[1] || name.toLowerCase();
|
|
44
|
+
content += `router.use('/${basePath}', ${name.toLowerCase()}Router);\n\n`;
|
|
45
|
+
content += `export default router;\n`;
|
|
46
|
+
}
|
|
47
|
+
await writeFile(routesPath, content);
|
|
48
|
+
}
|