create-backlist 1.3.3 → 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.
- package/package.json +1 -1
- package/src/analyzer.js +69 -4
- package/src/generators/node.js +81 -25
- package/src/templates/node-ts-express/partials/Controller.ts.ejs +57 -0
- package/src/templates/node-ts-express/partials/Model.ts.ejs +22 -0
- package/src/templates/node-ts-express/partials/routes.ts.ejs +50 -13
package/package.json
CHANGED
package/src/analyzer.js
CHANGED
|
@@ -3,12 +3,24 @@ const { glob } = require('glob');
|
|
|
3
3
|
const parser = require('@babel/parser');
|
|
4
4
|
const traverse = require('@babel/traverse').default;
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Converts a string to TitleCase, which is suitable for model and controller names.
|
|
8
|
+
* e.g., 'user-orders' -> 'UserOrders'
|
|
9
|
+
* @param {string} str The input string.
|
|
10
|
+
* @returns {string} The TitleCased string.
|
|
11
|
+
*/
|
|
6
12
|
function toTitleCase(str) {
|
|
7
13
|
if (!str) return 'Default';
|
|
8
|
-
return str.replace(
|
|
14
|
+
return str.replace(/-_(\w)/g, g => g[1].toUpperCase()) // handle snake_case and kebab-case
|
|
15
|
+
.replace(/\w\S*/g, txt => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase())
|
|
9
16
|
.replace(/[^a-zA-Z0-9]/g, '');
|
|
10
17
|
}
|
|
11
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Analyzes frontend source files to find API endpoints and their details.
|
|
21
|
+
* @param {string} srcPath The path to the frontend source directory.
|
|
22
|
+
* @returns {Promise<Array<object>>} A promise that resolves to an array of endpoint objects.
|
|
23
|
+
*/
|
|
12
24
|
async function analyzeFrontend(srcPath) {
|
|
13
25
|
if (!fs.existsSync(srcPath)) {
|
|
14
26
|
throw new Error(`The source directory '${srcPath}' does not exist.`);
|
|
@@ -21,39 +33,92 @@ async function analyzeFrontend(srcPath) {
|
|
|
21
33
|
const code = await fs.readFile(file, 'utf-8');
|
|
22
34
|
try {
|
|
23
35
|
const ast = parser.parse(code, { sourceType: 'module', plugins: ['jsx', 'typescript'] });
|
|
36
|
+
|
|
24
37
|
traverse(ast, {
|
|
25
38
|
CallExpression(path) {
|
|
39
|
+
// We are only interested in 'fetch' calls
|
|
26
40
|
if (path.node.callee.name !== 'fetch') return;
|
|
41
|
+
|
|
27
42
|
const urlNode = path.node.arguments[0];
|
|
28
43
|
|
|
29
44
|
let urlValue;
|
|
30
45
|
if (urlNode.type === 'StringLiteral') {
|
|
31
46
|
urlValue = urlNode.value;
|
|
32
47
|
} else if (urlNode.type === 'TemplateLiteral' && urlNode.quasis.length > 0) {
|
|
33
|
-
|
|
48
|
+
// Reconstruct path for dynamic URLs like `/api/users/${id}` -> `/api/users/{id}`
|
|
49
|
+
urlValue = urlNode.quasis.map((q, i) => {
|
|
50
|
+
return q.value.raw + (urlNode.expressions[i] ? `{${urlNode.expressions[i].name || 'id'}}` : '');
|
|
51
|
+
}).join('');
|
|
34
52
|
}
|
|
35
53
|
|
|
54
|
+
// Only process API calls that start with '/api/'
|
|
36
55
|
if (!urlValue || !urlValue.startsWith('/api/')) return;
|
|
37
56
|
|
|
38
57
|
let method = 'GET';
|
|
58
|
+
let schemaFields = null;
|
|
39
59
|
|
|
40
60
|
const optionsNode = path.node.arguments[1];
|
|
41
61
|
if (optionsNode && optionsNode.type === 'ObjectExpression') {
|
|
62
|
+
// Find the HTTP method
|
|
42
63
|
const methodProp = optionsNode.properties.find(p => p.key.name === 'method');
|
|
43
64
|
if (methodProp && methodProp.value.type === 'StringLiteral') {
|
|
44
65
|
method = methodProp.value.value.toUpperCase();
|
|
45
66
|
}
|
|
67
|
+
|
|
68
|
+
// --- NEW LOGIC: Analyze the 'body' for POST/PUT requests ---
|
|
69
|
+
if (method === 'POST' || method === 'PUT') {
|
|
70
|
+
const bodyProp = optionsNode.properties.find(p => p.key.name === 'body');
|
|
71
|
+
|
|
72
|
+
// Check if body is wrapped in JSON.stringify
|
|
73
|
+
if (bodyProp && bodyProp.value.callee && bodyProp.value.callee.name === 'JSON.stringify') {
|
|
74
|
+
const dataObjectNode = bodyProp.value.arguments[0];
|
|
75
|
+
|
|
76
|
+
// This is a simplified analysis assuming the object is defined inline.
|
|
77
|
+
// A more robust solution would trace variables back to their definition.
|
|
78
|
+
if (dataObjectNode.type === 'ObjectExpression') {
|
|
79
|
+
schemaFields = {};
|
|
80
|
+
dataObjectNode.properties.forEach(prop => {
|
|
81
|
+
const key = prop.key.name;
|
|
82
|
+
const valueNode = prop.value;
|
|
83
|
+
|
|
84
|
+
// Infer Mongoose schema type based on the value's literal type
|
|
85
|
+
if (valueNode.type === 'StringLiteral') {
|
|
86
|
+
schemaFields[key] = 'String';
|
|
87
|
+
} else if (valueNode.type === 'NumericLiteral') {
|
|
88
|
+
schemaFields[key] = 'Number';
|
|
89
|
+
} else if (valueNode.type === 'BooleanLiteral') {
|
|
90
|
+
schemaFields[key] = 'Boolean';
|
|
91
|
+
} else {
|
|
92
|
+
// Default to String if the type is complex or a variable
|
|
93
|
+
schemaFields[key] = 'String';
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
46
99
|
}
|
|
47
100
|
|
|
101
|
+
// Generate a clean controller name (e.g., /api/user-orders -> UserOrders)
|
|
48
102
|
const controllerName = toTitleCase(urlValue.split('/')[2]);
|
|
49
103
|
const key = `${method}:${urlValue}`;
|
|
104
|
+
|
|
105
|
+
// Avoid adding duplicate endpoints
|
|
50
106
|
if (!endpoints.has(key)) {
|
|
51
|
-
endpoints.set(key, {
|
|
107
|
+
endpoints.set(key, {
|
|
108
|
+
path: urlValue,
|
|
109
|
+
method,
|
|
110
|
+
controllerName,
|
|
111
|
+
schemaFields // This will be null for GET/DELETE, and an object for POST/PUT
|
|
112
|
+
});
|
|
52
113
|
}
|
|
53
114
|
},
|
|
54
115
|
});
|
|
55
|
-
} catch (e) {
|
|
116
|
+
} catch (e) {
|
|
117
|
+
// Ignore files that babel can't parse (e.g., CSS-in-JS files)
|
|
118
|
+
}
|
|
56
119
|
}
|
|
120
|
+
|
|
121
|
+
// Return all found endpoints as an array
|
|
57
122
|
return Array.from(endpoints.values());
|
|
58
123
|
}
|
|
59
124
|
|
package/src/generators/node.js
CHANGED
|
@@ -5,81 +5,137 @@ const path = require('path');
|
|
|
5
5
|
const { analyzeFrontend } = require('../analyzer');
|
|
6
6
|
const { renderAndWrite, getTemplatePath } = require('./template');
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Generate a Node.js + TypeScript (Express) backend project automatically.
|
|
10
|
+
*/
|
|
8
11
|
async function generateNodeProject(options) {
|
|
9
12
|
const { projectDir, projectName, frontendSrcDir } = options;
|
|
10
13
|
|
|
11
14
|
try {
|
|
12
15
|
// --- Step 1: Analyze Frontend ---
|
|
13
|
-
console.log(chalk.blue('
|
|
16
|
+
console.log(chalk.blue(' -> Analyzing frontend for API endpoints...'));
|
|
14
17
|
const endpoints = await analyzeFrontend(frontendSrcDir);
|
|
18
|
+
|
|
15
19
|
if (endpoints.length > 0) {
|
|
16
|
-
console.log(chalk.green(`
|
|
20
|
+
console.log(chalk.green(` -> Found ${endpoints.length} endpoints.`));
|
|
17
21
|
} else {
|
|
18
|
-
console.log(
|
|
22
|
+
console.log(
|
|
23
|
+
chalk.yellow(' -> No API endpoints found. A basic project will be created.')
|
|
24
|
+
);
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
// --- Step 2: Scaffold Base Project ---
|
|
22
28
|
console.log(chalk.blue(' -> Scaffolding Node.js (Express + TS) project...'));
|
|
23
|
-
|
|
24
|
-
// Define paths clearly
|
|
29
|
+
|
|
25
30
|
const baseDir = getTemplatePath('node-ts-express/base');
|
|
26
31
|
const serverTemplatePath = path.join(baseDir, 'server.ts');
|
|
27
32
|
const tsconfigTemplatePath = path.join(baseDir, 'tsconfig.json');
|
|
28
|
-
|
|
33
|
+
|
|
29
34
|
const destSrcDir = path.join(projectDir, 'src');
|
|
30
35
|
const serverDestPath = path.join(destSrcDir, 'server.ts');
|
|
31
36
|
const tsconfigDestPath = path.join(projectDir, 'tsconfig.json');
|
|
32
37
|
|
|
33
|
-
// Ensure destination directory exists
|
|
34
38
|
await fs.ensureDir(destSrcDir);
|
|
35
|
-
|
|
36
|
-
// Copy base files individually for clarity
|
|
37
39
|
await fs.copy(serverTemplatePath, serverDestPath);
|
|
38
40
|
await fs.copy(tsconfigTemplatePath, tsconfigDestPath);
|
|
39
|
-
|
|
40
|
-
console.log(chalk.gray(' -> Base server.ts copied.'));
|
|
41
|
-
|
|
42
|
-
// --- Step 3: Generate
|
|
41
|
+
|
|
42
|
+
console.log(chalk.gray(' -> Base server.ts and tsconfig.json copied.'));
|
|
43
|
+
|
|
44
|
+
// --- Step 3: Generate package.json and routes.ts ---
|
|
43
45
|
await renderAndWrite(
|
|
44
46
|
getTemplatePath('node-ts-express/partials/package.json.ejs'),
|
|
45
47
|
path.join(projectDir, 'package.json'),
|
|
46
48
|
{ projectName }
|
|
47
49
|
);
|
|
50
|
+
|
|
48
51
|
await renderAndWrite(
|
|
49
52
|
getTemplatePath('node-ts-express/partials/routes.ts.ejs'),
|
|
50
53
|
path.join(destSrcDir, 'routes.ts'),
|
|
51
54
|
{ endpoints }
|
|
52
55
|
);
|
|
53
|
-
|
|
56
|
+
|
|
54
57
|
console.log(chalk.gray(' -> package.json and routes.ts generated.'));
|
|
55
58
|
|
|
56
|
-
// --- Step 4:
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
// --- Step 4: Analyze endpoints for models/controllers ---
|
|
60
|
+
const modelsToGenerate = new Map();
|
|
61
|
+
|
|
62
|
+
endpoints.forEach((ep) => {
|
|
63
|
+
if (ep.schemaFields && !modelsToGenerate.has(ep.controllerName)) {
|
|
64
|
+
modelsToGenerate.set(ep.controllerName, ep.schemaFields);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// --- Step 5: Generate Models and Controllers if applicable ---
|
|
69
|
+
if (modelsToGenerate.size > 0) {
|
|
70
|
+
console.log(chalk.blue(' -> Generating database models and controllers...'));
|
|
71
|
+
|
|
72
|
+
await fs.ensureDir(path.join(projectDir, 'src', 'models'));
|
|
73
|
+
await fs.ensureDir(path.join(projectDir, 'src', 'controllers'));
|
|
74
|
+
|
|
75
|
+
for (const [modelName, schema] of modelsToGenerate.entries()) {
|
|
76
|
+
// Generate Model file
|
|
77
|
+
await renderAndWrite(
|
|
78
|
+
getTemplatePath('node-ts-express/partials/Model.ts.ejs'),
|
|
79
|
+
path.join(projectDir, 'src', 'models', `${modelName}.model.ts`),
|
|
80
|
+
{ modelName, schema }
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
// Generate Controller file
|
|
84
|
+
await renderAndWrite(
|
|
85
|
+
getTemplatePath('node-ts-express/partials/Controller.ts.ejs'),
|
|
86
|
+
path.join(projectDir, 'src', 'controllers', `${modelName}.controller.ts`),
|
|
87
|
+
{ modelName }
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
console.log(chalk.gray(' -> Models and controllers generated.'));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// --- Step 6: Modify server.ts ---
|
|
95
|
+
if (!(await fs.pathExists(serverDestPath))) {
|
|
96
|
+
throw new Error(`Critical error: server.ts was not found at ${serverDestPath}.`);
|
|
60
97
|
}
|
|
61
|
-
|
|
98
|
+
|
|
62
99
|
let serverFileContent = await fs.readFile(serverDestPath, 'utf-8');
|
|
63
|
-
serverFileContent = serverFileContent.replace(
|
|
100
|
+
serverFileContent = serverFileContent.replace(
|
|
101
|
+
'// INJECT:ROUTES',
|
|
102
|
+
`import apiRoutes from './routes';\napp.use(apiRoutes);`
|
|
103
|
+
);
|
|
64
104
|
await fs.writeFile(serverDestPath, serverFileContent);
|
|
65
105
|
|
|
66
106
|
console.log(chalk.gray(' -> server.ts modified successfully.'));
|
|
67
107
|
|
|
68
|
-
// --- Step
|
|
108
|
+
// --- Step 7: Install dependencies ---
|
|
69
109
|
console.log(chalk.magenta(' -> Installing dependencies (npm install)...'));
|
|
70
110
|
await execa('npm', ['install'], { cwd: projectDir });
|
|
71
111
|
|
|
72
|
-
// --- Step
|
|
112
|
+
// --- Step 8: Add mongoose if models were generated ---
|
|
113
|
+
if (modelsToGenerate.size > 0) {
|
|
114
|
+
console.log(chalk.gray(' -> Adding Mongoose to dependencies...'));
|
|
115
|
+
|
|
116
|
+
const packageJsonPath = path.join(projectDir, 'package.json');
|
|
117
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
118
|
+
packageJson.dependencies = packageJson.dependencies || {};
|
|
119
|
+
packageJson.dependencies['mongoose'] = '^7.5.0';
|
|
120
|
+
|
|
121
|
+
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
122
|
+
|
|
123
|
+
console.log(chalk.magenta(' -> Installing new dependencies (mongoose)...'));
|
|
124
|
+
await execa('npm', ['install'], { cwd: projectDir });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// --- Step 9: Generate README ---
|
|
73
128
|
await renderAndWrite(
|
|
74
129
|
getTemplatePath('node-ts-express/partials/README.md.ejs'),
|
|
75
130
|
path.join(projectDir, 'README.md'),
|
|
76
131
|
{ projectName }
|
|
77
132
|
);
|
|
78
133
|
|
|
134
|
+
console.log(chalk.green('✅ Project generation completed successfully!'));
|
|
79
135
|
} catch (error) {
|
|
80
|
-
|
|
81
|
-
throw error;
|
|
136
|
+
console.error(chalk.red('❌ Error generating Node project:'), error);
|
|
137
|
+
throw error; // Pass to main CLI handler
|
|
82
138
|
}
|
|
83
139
|
}
|
|
84
140
|
|
|
85
|
-
module.exports = { generateNodeProject };
|
|
141
|
+
module.exports = { generateNodeProject };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// Auto-generated by create-backlist on <%= new Date().toISOString() %>
|
|
2
|
+
import { Request, Response } from 'express';
|
|
3
|
+
import <%= modelName %>, { I<%= modelName %> } from '../models/<%= modelName %>.model';
|
|
4
|
+
|
|
5
|
+
// @desc Create a new <%= modelName %>
|
|
6
|
+
export const create<%= modelName %> = async (req: Request, res: Response) => {
|
|
7
|
+
try {
|
|
8
|
+
const newDoc = new <%= modelName %>(req.body);
|
|
9
|
+
await newDoc.save();
|
|
10
|
+
res.status(201).json(newDoc);
|
|
11
|
+
} catch (error) {
|
|
12
|
+
res.status(500).json({ message: 'Error creating document', error });
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// @desc Get all <%= modelName %>s
|
|
17
|
+
export const getAll<%= modelName %>s = async (req: Request, res: Response) => {
|
|
18
|
+
try {
|
|
19
|
+
const docs = await <%= modelName %>.find();
|
|
20
|
+
res.status(200).json(docs);
|
|
21
|
+
} catch (error) {
|
|
22
|
+
res.status(500).json({ message: 'Error fetching documents', error });
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// @desc Get a single <%= modelName %> by ID
|
|
27
|
+
export const get<%= modelName %>ById = async (req: Request, res: Response) => {
|
|
28
|
+
try {
|
|
29
|
+
const doc = await <%= modelName %>.findById(req.params.id);
|
|
30
|
+
if (!doc) return res.status(404).json({ message: 'Document not found' });
|
|
31
|
+
res.status(200).json(doc);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
res.status(500).json({ message: 'Error fetching document', error });
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// @desc Update a <%= modelName %> by ID
|
|
38
|
+
export const update<%= modelName %>ById = async (req: Request, res: Response) => {
|
|
39
|
+
try {
|
|
40
|
+
const doc = await <%= modelName %>.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
|
|
41
|
+
if (!doc) return res.status(404).json({ message: 'Document not found' });
|
|
42
|
+
res.status(200).json(doc);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
res.status(500).json({ message: 'Error updating document', error });
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// @desc Delete a <%= modelName %> by ID
|
|
49
|
+
export const delete<%= modelName %>ById = async (req: Request, res: Response) => {
|
|
50
|
+
try {
|
|
51
|
+
const doc = await <%= modelName %>.findByIdAndDelete(req.params.id);
|
|
52
|
+
if (!doc) return res.status(404).json({ message: 'Document not found' });
|
|
53
|
+
res.status(200).json({ message: 'Document deleted successfully' });
|
|
54
|
+
} catch (error) {
|
|
55
|
+
res.status(500).json({ message: 'Error deleting document', error });
|
|
56
|
+
}
|
|
57
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Auto-generated by create-backlist on <%= new Date().toISOString() %>
|
|
2
|
+
import mongoose, { Schema, Document } from 'mongoose';
|
|
3
|
+
|
|
4
|
+
// Define the interface for the Document
|
|
5
|
+
export interface I<%= modelName %> extends Document {
|
|
6
|
+
<% Object.keys(schema).forEach(key => { %>
|
|
7
|
+
<%= key %>: <%= schema[key].toLowerCase() %>;
|
|
8
|
+
<% }); %>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Define the Mongoose Schema
|
|
12
|
+
const <%= modelName %>Schema: Schema = new Schema({
|
|
13
|
+
<% Object.keys(schema).forEach(key => { %>
|
|
14
|
+
<%= key %>: {
|
|
15
|
+
type: <%= schema[key] %>,
|
|
16
|
+
// TODO: Add 'required', 'unique', etc. here
|
|
17
|
+
},
|
|
18
|
+
<% }); %>
|
|
19
|
+
}, { timestamps: true });
|
|
20
|
+
|
|
21
|
+
// Create and export the Model
|
|
22
|
+
export default mongoose.model<I<%= modelName %>>('<%= modelName %>', <%= modelName %>Schema);
|
|
@@ -1,23 +1,60 @@
|
|
|
1
|
-
// Auto-generated by
|
|
1
|
+
// Auto-generated by create-backlist on <%= new Date().toISOString() %>
|
|
2
2
|
import { Router, Request, Response } from 'express';
|
|
3
|
+
<%# Create a unique set of controller names from the endpoints array %>
|
|
4
|
+
<% const controllersToImport = new Set(endpoints.map(ep => ep.controllerName).filter(name => name !== 'Default')); %>
|
|
5
|
+
|
|
6
|
+
// Import all the generated controllers
|
|
7
|
+
<% for (const controller of controllersToImport) { %>
|
|
8
|
+
import * as <%= controller %>Controller from '../controllers/<%= controller %>.controller';
|
|
9
|
+
<% } %>
|
|
3
10
|
|
|
4
11
|
const router = Router();
|
|
5
12
|
|
|
6
|
-
|
|
7
|
-
// No API endpoints were detected in the frontend code. Add your routes here.
|
|
8
|
-
<% } else { %>
|
|
13
|
+
<%# Loop through each endpoint found by the analyzer %>
|
|
9
14
|
<% endpoints.forEach(endpoint => { %>
|
|
10
|
-
|
|
11
|
-
|
|
15
|
+
<%
|
|
16
|
+
// Convert URL path for Express router (e.g., /api/users/{id} -> /users/:id)
|
|
17
|
+
const expressPath = endpoint.path.replace('/api', '').replace(/{(\w+)}/g, ':$1');
|
|
18
|
+
const controllerName = endpoint.controllerName;
|
|
19
|
+
let handlerFunction;
|
|
20
|
+
|
|
21
|
+
// --- LOGIC TO MAP ENDPOINT TO A CRUD CONTROLLER FUNCTION ---
|
|
22
|
+
// This logic assumes a standard RESTful API structure.
|
|
23
|
+
|
|
24
|
+
if (controllerName !== 'Default') {
|
|
25
|
+
if (endpoint.method === 'POST' && !expressPath.includes(':')) {
|
|
26
|
+
// e.g., POST /users -> create a new user
|
|
27
|
+
handlerFunction = `${controllerName}Controller.create${controllerName}`;
|
|
28
|
+
} else if (endpoint.method === 'GET' && !expressPath.includes(':')) {
|
|
29
|
+
// e.g., GET /users -> get all users
|
|
30
|
+
handlerFunction = `${controllerName}Controller.getAll${controllerName}s`;
|
|
31
|
+
} else if (endpoint.method === 'GET' && expressPath.includes(':')) {
|
|
32
|
+
// e.g., GET /users/:id -> get a single user by ID
|
|
33
|
+
handlerFunction = `${controllerName}Controller.get${controllerName}ById`;
|
|
34
|
+
} else if (endpoint.method === 'PUT' && expressPath.includes(':')) {
|
|
35
|
+
// e.g., PUT /users/:id -> update a user by ID
|
|
36
|
+
handlerFunction = `${controllerName}Controller.update${controllerName}ById`;
|
|
37
|
+
} else if (endpoint.method === 'DELETE' && expressPath.includes(':')) {
|
|
38
|
+
// e.g., DELETE /users/:id -> delete a user by ID
|
|
39
|
+
handlerFunction = `${controllerName}Controller.delete${controllerName}ById`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// If no specific CRUD function matches, or if it's a default/unhandled route,
|
|
44
|
+
// create a simple placeholder function.
|
|
45
|
+
if (!handlerFunction) {
|
|
46
|
+
handlerFunction = `(req: Request, res: Response) => {
|
|
47
|
+
// TODO: Implement logic for this custom endpoint
|
|
48
|
+
res.status(501).json({ message: 'Handler not implemented for <%= endpoint.method %> <%= expressPath %>' });
|
|
49
|
+
}`;
|
|
50
|
+
}
|
|
51
|
+
%>
|
|
12
52
|
/**
|
|
13
|
-
*
|
|
53
|
+
* Route for <%= endpoint.method.toUpperCase() %> <%= endpoint.path %>
|
|
54
|
+
* Mapped to: <%- handlerFunction.includes('=>') ? 'Inline Handler' : handlerFunction %>
|
|
14
55
|
*/
|
|
15
|
-
router.<%= endpoint.method.toLowerCase() %>('<%- expressPath %>',
|
|
16
|
-
|
|
17
|
-
// TODO: Implement your logic here.
|
|
18
|
-
res.status(200).json({ message: 'Auto-generated response for <%= endpoint.path %>' });
|
|
19
|
-
});
|
|
56
|
+
router.<%= endpoint.method.toLowerCase() %>('<%- expressPath %>', <%- handlerFunction %>);
|
|
57
|
+
|
|
20
58
|
<% }); %>
|
|
21
|
-
<% } %>
|
|
22
59
|
|
|
23
60
|
export default router;
|