create-backlist 2.0.0 β 2.0.1
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/LICENSE +21 -0
- package/README.md +97 -0
- package/package.json +1 -1
- package/src/generators/node.js +75 -87
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) [2025] [W.A.H.ISHAN]
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# π Create Backlist
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/create-backlist)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
Tired of manually creating backend boilerplate every time you build a frontend? **`create-backlist`** is an intelligent CLI tool that analyzes your frontend project and automatically generates a backend with all the necessary routes and controllers, saving you hours of repetitive work.
|
|
7
|
+
|
|
8
|
+
It's not just another scaffolder; it's a **context-aware, dynamic code generator** that builds a backend tailor-made for your frontend's specific API needs.
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
## β¨ Key Features
|
|
13
|
+
|
|
14
|
+
- **π€ Intelligent Code Analysis:** Scans your frontend codebase (React, Vue, etc.) using Abstract Syntax Trees (ASTs) to detect API calls (`fetch` requests).
|
|
15
|
+
- **π Multi-Language Support:** Generate a backend in your preferred stack.
|
|
16
|
+
- β
**Currently Supports:**
|
|
17
|
+
- Node.js (with TypeScript & Express)
|
|
18
|
+
- C# (with ASP.NET Core Web API)
|
|
19
|
+
- β³ **Coming Soon:**
|
|
20
|
+
- Python (with FastAPI)
|
|
21
|
+
- Java (with Spring Boot)
|
|
22
|
+
- **β‘οΈ Fully Automated:** A single command handles everything from project scaffolding to dependency installation.
|
|
23
|
+
- **π§ Zero-Configuration:** No complex config files needed. Just run the command and answer a few simple questions.
|
|
24
|
+
- **π§Ό Clean Code Generation:** Creates a well-structured backend, ready for you to implement your business logic.
|
|
25
|
+
|
|
26
|
+
## π¦ Installation & Usage
|
|
27
|
+
|
|
28
|
+
No global installation needed! Just run this command inside your existing frontend project's root directory:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm create backlist@latest
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The tool will then guide you through an interactive setup process:
|
|
35
|
+
|
|
36
|
+
1. **Enter a name for your backend directory:** (default: `backend`)
|
|
37
|
+
2. **Select the backend stack:** (e.g., `Node.js (TypeScript, Express)`)
|
|
38
|
+
3. **Enter the path to your frontend `src` directory:** (default: `src`)
|
|
39
|
+
|
|
40
|
+
That's it! The tool will analyze your code, generate the backend in a new directory, and install all the necessary dependencies.
|
|
41
|
+
|
|
42
|
+
### Example
|
|
43
|
+
|
|
44
|
+
Let's say your frontend has this API call:
|
|
45
|
+
|
|
46
|
+
```javascript
|
|
47
|
+
// in your React component
|
|
48
|
+
fetch('/api/products/123', { method: 'PUT' });
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`create-backlist` will automatically generate a backend with a `products` controller and a `PUT` route for `products/:id`.
|
|
52
|
+
|
|
53
|
+
## π‘ How It's Different from Other Tools
|
|
54
|
+
|
|
55
|
+
| Tool | Approach | Use Case |
|
|
56
|
+
| --------------------- | -------------------------------------- | ----------------------------------------------------------- |
|
|
57
|
+
| **Express Generator** | Static Scaffolding | Quickly start a *new, empty* Express project. |
|
|
58
|
+
| **NestJS CLI** | Static Scaffolding & Code Generation | Start a *new, structured* NestJS project and add parts manually. |
|
|
59
|
+
| **`create-backlist`** | **Dynamic & Context-Aware Scaffolding** | Generate a backend that is **tailor-made** for an *existing* frontend. |
|
|
60
|
+
|
|
61
|
+
While traditional generators give you a blank canvas, `create-backlist` looks at your finished painting (the frontend) and builds the perfect frame (the backend) for it.
|
|
62
|
+
|
|
63
|
+
## πΊοΈ Roadmap
|
|
64
|
+
|
|
65
|
+
`create-backlist` is actively being developed. Here are some of the features planned for future releases:
|
|
66
|
+
|
|
67
|
+
- [ ] **Python Support:** Generate a backend using FastAPI.
|
|
68
|
+
- [ ] **Java Support:** Generate a backend using Spring Boot.
|
|
69
|
+
- [ ] **Database Model Generation:** Automatically create basic database models (e.g., Mongoose, Prisma) based on `POST`/`PUT` request bodies.
|
|
70
|
+
- [ ] **Authentication Boilerplate:** Add an option to generate basic JWT-based authentication routes (`/login`, `/register`).
|
|
71
|
+
|
|
72
|
+
Have an idea for a new feature? Feel free to [open an issue](https://github.com/WAH-ISHAN/create-backlist/issues) on GitHub!
|
|
73
|
+
|
|
74
|
+
## π οΈ Contributing
|
|
75
|
+
|
|
76
|
+
Contributions are what make the open-source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
|
|
77
|
+
|
|
78
|
+
1. Fork the Project
|
|
79
|
+
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
|
|
80
|
+
3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
|
|
81
|
+
4. Push to the Branch (`git push origin feature/AmazingFeature`)
|
|
82
|
+
5. Open a Pull Request
|
|
83
|
+
|
|
84
|
+
## π License
|
|
85
|
+
|
|
86
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
87
|
+
|
|
88
|
+
## π Acknowledgements
|
|
89
|
+
|
|
90
|
+
- **Babel** for the amazing AST parser.
|
|
91
|
+
- **Inquirer.js** for the interactive CLI prompts.
|
|
92
|
+
- **fs-extra** for making file system operations a breeze.
|
|
93
|
+
- **Google's Gemini** for assistance with brainstorming and debugging.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
_Built with β€οΈ by [W.A.H. ISHAN](https://github.com/WAH-ISHAN)._
|
package/package.json
CHANGED
package/src/generators/node.js
CHANGED
|
@@ -5,137 +5,125 @@ 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
|
-
*/
|
|
11
8
|
async function generateNodeProject(options) {
|
|
12
9
|
const { projectDir, projectName, frontendSrcDir } = options;
|
|
13
10
|
|
|
14
11
|
try {
|
|
15
|
-
// --- Step 1: Analyze Frontend ---
|
|
16
|
-
console.log(chalk.blue('
|
|
12
|
+
// --- Step 1: Analyze Frontend to get Endpoints and Schema Info ---
|
|
13
|
+
console.log(chalk.blue(' -> Analyzing frontend for API endpoints...'));
|
|
17
14
|
const endpoints = await analyzeFrontend(frontendSrcDir);
|
|
18
|
-
|
|
19
15
|
if (endpoints.length > 0) {
|
|
20
|
-
console.log(chalk.green(`
|
|
16
|
+
console.log(chalk.green(` -> Found ${endpoints.length} endpoints.`));
|
|
21
17
|
} else {
|
|
22
|
-
console.log(
|
|
23
|
-
chalk.yellow(' -> No API endpoints found. A basic project will be created.')
|
|
24
|
-
);
|
|
18
|
+
console.log(chalk.yellow(' -> No API endpoints found. A basic project will be created.'));
|
|
25
19
|
}
|
|
26
20
|
|
|
27
|
-
// --- Step 2:
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
21
|
+
// --- Step 2: Identify which Database Models to Generate ---
|
|
22
|
+
const modelsToGenerate = new Map();
|
|
23
|
+
endpoints.forEach(ep => {
|
|
24
|
+
// If an endpoint has schemaFields and a valid controllerName, add it to our map.
|
|
25
|
+
if (ep.schemaFields && ep.controllerName !== 'Default' && !modelsToGenerate.has(ep.controllerName)) {
|
|
26
|
+
modelsToGenerate.set(ep.controllerName, ep.schemaFields);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
33
29
|
|
|
30
|
+
// --- Step 3: Scaffold Base Project Structure & Files ---
|
|
31
|
+
console.log(chalk.blue(' -> Scaffolding Node.js (Express + TS) project...'));
|
|
32
|
+
|
|
33
|
+
// Create the main source directory
|
|
34
34
|
const destSrcDir = path.join(projectDir, 'src');
|
|
35
|
-
const serverDestPath = path.join(destSrcDir, 'server.ts');
|
|
36
|
-
const tsconfigDestPath = path.join(projectDir, 'tsconfig.json');
|
|
37
|
-
|
|
38
35
|
await fs.ensureDir(destSrcDir);
|
|
39
|
-
await fs.copy(serverTemplatePath, serverDestPath);
|
|
40
|
-
await fs.copy(tsconfigTemplatePath, tsconfigDestPath);
|
|
41
|
-
|
|
42
|
-
console.log(chalk.gray(' -> Base server.ts and tsconfig.json copied.'));
|
|
43
36
|
|
|
44
|
-
//
|
|
45
|
-
await
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
);
|
|
37
|
+
// Copy static base files
|
|
38
|
+
await fs.copy(getTemplatePath('node-ts-express/base/server.ts'), path.join(destSrcDir, 'server.ts'));
|
|
39
|
+
await fs.copy(getTemplatePath('node-ts-express/base/tsconfig.json'), path.join(projectDir, 'tsconfig.json'));
|
|
40
|
+
|
|
41
|
+
// --- Step 4: Generate Dynamic Files (package.json, Models, Controllers) ---
|
|
50
42
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
{ endpoints }
|
|
43
|
+
// Prepare package.json content (in memory)
|
|
44
|
+
const packageJsonContent = JSON.parse(
|
|
45
|
+
await ejs.renderFile(getTemplatePath('node-ts-express/partials/package.json.ejs'), { projectName })
|
|
55
46
|
);
|
|
56
47
|
|
|
57
|
-
|
|
58
|
-
|
|
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 ---
|
|
48
|
+
// Conditionally add Mongoose if we are generating models
|
|
69
49
|
if (modelsToGenerate.size > 0) {
|
|
70
|
-
console.log(chalk.
|
|
50
|
+
console.log(chalk.gray(' -> Preparing to add Mongoose to dependencies...'));
|
|
51
|
+
packageJsonContent.dependencies['mongoose'] = '^7.5.0'; // Use a recent, stable version
|
|
52
|
+
}
|
|
71
53
|
|
|
72
|
-
|
|
73
|
-
|
|
54
|
+
// Write the final package.json to the disk
|
|
55
|
+
await fs.writeJson(path.join(projectDir, 'package.json'), packageJsonContent, { spaces: 2 });
|
|
56
|
+
|
|
57
|
+
// Generate Model and Controller files if any were found
|
|
58
|
+
if (modelsToGenerate.size > 0) {
|
|
59
|
+
console.log(chalk.blue(' -> Generating database models and controllers...'));
|
|
60
|
+
await fs.ensureDir(path.join(destSrcDir, 'models'));
|
|
61
|
+
await fs.ensureDir(path.join(destSrcDir, 'controllers'));
|
|
74
62
|
|
|
75
63
|
for (const [modelName, schema] of modelsToGenerate.entries()) {
|
|
76
|
-
// Generate Model
|
|
64
|
+
// Generate Model File (e.g., models/User.model.ts)
|
|
77
65
|
await renderAndWrite(
|
|
78
66
|
getTemplatePath('node-ts-express/partials/Model.ts.ejs'),
|
|
79
|
-
path.join(
|
|
67
|
+
path.join(destSrcDir, 'models', `${modelName}.model.ts`),
|
|
80
68
|
{ modelName, schema }
|
|
81
69
|
);
|
|
82
|
-
|
|
83
|
-
// Generate Controller file
|
|
70
|
+
// Generate Controller File (e.g., controllers/User.controller.ts)
|
|
84
71
|
await renderAndWrite(
|
|
85
72
|
getTemplatePath('node-ts-express/partials/Controller.ts.ejs'),
|
|
86
|
-
path.join(
|
|
73
|
+
path.join(destSrcDir, 'controllers', `${modelName}.controller.ts`),
|
|
87
74
|
{ modelName }
|
|
88
75
|
);
|
|
89
76
|
}
|
|
90
|
-
|
|
91
|
-
console.log(chalk.gray(' -> Models and controllers generated.'));
|
|
92
77
|
}
|
|
93
78
|
|
|
94
|
-
// --- Step
|
|
95
|
-
|
|
96
|
-
|
|
79
|
+
// --- Step 5: Generate the Smart Route File ---
|
|
80
|
+
console.log(chalk.gray(' -> Generating dynamic routes...'));
|
|
81
|
+
await renderAndWrite(
|
|
82
|
+
getTemplatePath('node-ts-express/partials/routes.ts.ejs'),
|
|
83
|
+
path.join(destSrcDir, 'routes.ts'),
|
|
84
|
+
{ endpoints } // Pass all endpoints to the template
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
// --- Step 6: Inject Routes into the Main Server File ---
|
|
88
|
+
const serverDestPath = path.join(destSrcDir, 'server.ts');
|
|
89
|
+
let serverFileContent = await fs.readFile(serverDestPath, 'utf-8');
|
|
90
|
+
|
|
91
|
+
let dbConnectionCode = '';
|
|
92
|
+
if (modelsToGenerate.size > 0) {
|
|
93
|
+
dbConnectionCode = `
|
|
94
|
+
// --- Database Connection ---
|
|
95
|
+
import mongoose from 'mongoose';
|
|
96
|
+
const MONGO_URI = process.env.MONGO_URI || 'mongodb://localhost:27017/${projectName}';
|
|
97
|
+
mongoose.connect(MONGO_URI)
|
|
98
|
+
.then(() => console.log('MongoDB Connected...'))
|
|
99
|
+
.catch(err => console.error('MongoDB Connection Error:', err));
|
|
100
|
+
// -------------------------
|
|
101
|
+
`;
|
|
97
102
|
}
|
|
98
103
|
|
|
99
|
-
|
|
100
|
-
serverFileContent = serverFileContent
|
|
101
|
-
|
|
102
|
-
`import apiRoutes from './routes';\napp.use(apiRoutes);`
|
|
103
|
-
|
|
104
|
+
// Inject DB connection code after dotenv.config() and route loader
|
|
105
|
+
serverFileContent = serverFileContent
|
|
106
|
+
.replace("dotenv.config();", `dotenv.config();\n${dbConnectionCode}`)
|
|
107
|
+
.replace('// INJECT:ROUTES', `import apiRoutes from './routes';\napp.use(apiRoutes);`);
|
|
108
|
+
|
|
104
109
|
await fs.writeFile(serverDestPath, serverFileContent);
|
|
105
110
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
// --- Step 7: Install dependencies ---
|
|
109
|
-
console.log(chalk.magenta(' -> Installing dependencies (npm install)...'));
|
|
111
|
+
// --- Step 7: Install All Dependencies at Once ---
|
|
112
|
+
console.log(chalk.magenta(' -> Installing dependencies (npm install)... This might take a moment.'));
|
|
110
113
|
await execa('npm', ['install'], { cwd: projectDir });
|
|
111
114
|
|
|
112
|
-
// --- Step 8:
|
|
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 ---
|
|
115
|
+
// --- Step 8: Generate README ---
|
|
128
116
|
await renderAndWrite(
|
|
129
117
|
getTemplatePath('node-ts-express/partials/README.md.ejs'),
|
|
130
118
|
path.join(projectDir, 'README.md'),
|
|
131
119
|
{ projectName }
|
|
132
120
|
);
|
|
133
121
|
|
|
134
|
-
console.log(chalk.green('β
Project generation completed successfully!'));
|
|
135
122
|
} catch (error) {
|
|
136
|
-
|
|
137
|
-
|
|
123
|
+
// Re-throw the error so it can be caught by the main CLI handler in index.js
|
|
124
|
+
// This allows for centralized error message display and cleanup.
|
|
125
|
+
throw error;
|
|
138
126
|
}
|
|
139
127
|
}
|
|
140
128
|
|
|
141
|
-
module.exports = { generateNodeProject };
|
|
129
|
+
module.exports = { generateNodeProject };
|