create-backlist 7.3.0 → 7.4.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 (45) hide show
  1. package/bin/index.js +483 -470
  2. package/bin/qa.js +103 -0
  3. package/package.json +7 -3
  4. package/src/analyzer.js +221 -21
  5. package/src/env-resolver.js +70 -0
  6. package/src/generators/dotnet.js +134 -134
  7. package/src/generators/java.js +248 -248
  8. package/src/generators/js.js +345 -345
  9. package/src/generators/nestjs.js +277 -277
  10. package/src/generators/python.js +86 -86
  11. package/src/project-detector.js +131 -0
  12. package/src/qa/qa-engine.js +909 -0
  13. package/src/templates/dotnet/partials/Dockerfile.ejs +27 -27
  14. package/src/templates/dotnet/partials/docker-compose.yml.ejs +33 -33
  15. package/src/templates/js-express/base/server.js +59 -59
  16. package/src/templates/js-express/partials/Dockerfile.ejs +12 -12
  17. package/src/templates/js-express/partials/auth.controller.js.ejs +66 -66
  18. package/src/templates/js-express/partials/auth.middleware.js.ejs +19 -19
  19. package/src/templates/js-express/partials/auth.routes.js.ejs +9 -9
  20. package/src/templates/js-express/partials/controller.js.ejs +53 -53
  21. package/src/templates/js-express/partials/db.js.ejs +19 -19
  22. package/src/templates/js-express/partials/docker-compose.yml.ejs +46 -46
  23. package/src/templates/js-express/partials/model.js.ejs +18 -18
  24. package/src/templates/js-express/partials/package.json.ejs +17 -17
  25. package/src/templates/js-express/partials/prisma.schema.ejs +21 -21
  26. package/src/templates/js-express/partials/routes.js.ejs +19 -19
  27. package/src/templates/js-express/partials/seeder.js.ejs +103 -103
  28. package/src/templates/js-express/partials/service.js.ejs +51 -51
  29. package/src/templates/js-express/partials/swagger.js.ejs +30 -30
  30. package/src/templates/js-express/partials/test.js.ejs +46 -46
  31. package/src/templates/nestjs/base/app.module.ts +9 -9
  32. package/src/templates/nestjs/base/main.ts +23 -23
  33. package/src/templates/nestjs/base/tsconfig.json +21 -21
  34. package/src/templates/nestjs/partials/auth.controller.ts.ejs +17 -17
  35. package/src/templates/nestjs/partials/auth.module.ts.ejs +17 -17
  36. package/src/templates/nestjs/partials/auth.service.ts.ejs +70 -70
  37. package/src/templates/nestjs/partials/controller.ts.ejs +34 -34
  38. package/src/templates/nestjs/partials/create-dto.ts.ejs +22 -22
  39. package/src/templates/nestjs/partials/jwt-guard.ts.ejs +24 -24
  40. package/src/templates/nestjs/partials/module.ts.ejs +10 -10
  41. package/src/templates/nestjs/partials/package.json.ejs +27 -27
  42. package/src/templates/nestjs/partials/prisma.service.ts.ejs +13 -13
  43. package/src/templates/nestjs/partials/schema.ts.ejs +19 -19
  44. package/src/templates/nestjs/partials/service.ts.ejs +67 -67
  45. package/src/templates/nestjs/partials/update-dto.ts.ejs +4 -4
@@ -1,27 +1,27 @@
1
- # Auto-generated by create-backlist (.NET Core)
2
-
3
- # ---- Build Stage ----
4
- FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
5
- WORKDIR /src
6
-
7
- COPY *.csproj .
8
- RUN dotnet restore
9
-
10
- COPY . .
11
- RUN dotnet publish -c Release -o /app/publish --no-restore
12
-
13
- # ---- Runtime Stage ----
14
- FROM mcr.microsoft.com/dotnet/aspnet:8.0
15
- WORKDIR /app
16
-
17
- ENV ASPNETCORE_URLS=http://+:5000
18
- ENV ASPNETCORE_ENVIRONMENT=Production
19
-
20
- COPY --from=build /app/publish .
21
-
22
- EXPOSE 5000
23
-
24
- HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
25
- CMD curl -f http://localhost:5000/health || exit 1
26
-
27
- ENTRYPOINT ["dotnet", "<%= projectName %>.dll"]
1
+ # Auto-generated by create-backlist (.NET Core)
2
+
3
+ # ---- Build Stage ----
4
+ FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
5
+ WORKDIR /src
6
+
7
+ COPY *.csproj .
8
+ RUN dotnet restore
9
+
10
+ COPY . .
11
+ RUN dotnet publish -c Release -o /app/publish --no-restore
12
+
13
+ # ---- Runtime Stage ----
14
+ FROM mcr.microsoft.com/dotnet/aspnet:8.0
15
+ WORKDIR /app
16
+
17
+ ENV ASPNETCORE_URLS=http://+:5000
18
+ ENV ASPNETCORE_ENVIRONMENT=Production
19
+
20
+ COPY --from=build /app/publish .
21
+
22
+ EXPOSE 5000
23
+
24
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
25
+ CMD curl -f http://localhost:5000/health || exit 1
26
+
27
+ ENTRYPOINT ["dotnet", "<%= projectName %>.dll"]
@@ -1,33 +1,33 @@
1
- # Auto-generated by create-backlist (.NET Core)
2
- version: '3.8'
3
-
4
- services:
5
- app:
6
- build: .
7
- ports:
8
- - "5000:5000"
9
- environment:
10
- - ASPNETCORE_ENVIRONMENT=Development
11
- - ConnectionStrings__DefaultConnection=Host=db;Port=5432;Database=<%= projectName %>;Username=postgres;Password=postgres
12
- depends_on:
13
- db:
14
- condition: service_healthy
15
-
16
- db:
17
- image: postgres:16-alpine
18
- environment:
19
- POSTGRES_USER: postgres
20
- POSTGRES_PASSWORD: postgres
21
- POSTGRES_DB: <%= projectName %>
22
- ports:
23
- - "5432:5432"
24
- volumes:
25
- - pgdata:/var/lib/postgresql/data
26
- healthcheck:
27
- test: ["CMD-SHELL", "pg_isready -U postgres"]
28
- interval: 5s
29
- timeout: 3s
30
- retries: 5
31
-
32
- volumes:
33
- pgdata:
1
+ # Auto-generated by create-backlist (.NET Core)
2
+ version: '3.8'
3
+
4
+ services:
5
+ app:
6
+ build: .
7
+ ports:
8
+ - "5000:5000"
9
+ environment:
10
+ - ASPNETCORE_ENVIRONMENT=Development
11
+ - ConnectionStrings__DefaultConnection=Host=db;Port=5432;Database=<%= projectName %>;Username=postgres;Password=postgres
12
+ depends_on:
13
+ db:
14
+ condition: service_healthy
15
+
16
+ db:
17
+ image: postgres:16-alpine
18
+ environment:
19
+ POSTGRES_USER: postgres
20
+ POSTGRES_PASSWORD: postgres
21
+ POSTGRES_DB: <%= projectName %>
22
+ ports:
23
+ - "5432:5432"
24
+ volumes:
25
+ - pgdata:/var/lib/postgresql/data
26
+ healthcheck:
27
+ test: ["CMD-SHELL", "pg_isready -U postgres"]
28
+ interval: 5s
29
+ timeout: 3s
30
+ retries: 5
31
+
32
+ volumes:
33
+ pgdata:
@@ -1,59 +1,59 @@
1
- import express from 'express';
2
- import cors from 'cors';
3
- import dotenv from 'dotenv';
4
- import helmet from 'helmet';
5
- import morgan from 'morgan';
6
-
7
- dotenv.config();
8
-
9
- const app = express();
10
-
11
- app.use(helmet());
12
- app.use(morgan(process.env.NODE_ENV === 'production' ? 'combined' : 'dev'));
13
-
14
- app.use(cors({
15
- origin: process.env.CORS_ORIGIN
16
- ? process.env.CORS_ORIGIN.split(',').map(s => s.trim())
17
- : ['http://localhost:3000', 'http://localhost:5173'],
18
- credentials: true,
19
- }));
20
-
21
- app.use(express.json({ limit: '1mb' }));
22
-
23
- app.get('/api/health', (req, res) => {
24
- res.status(200).json({ status: 'ok' });
25
- });
26
-
27
- app.get('/', (req, res) => {
28
- res.send('Backend is running! Generated by create-backlist.');
29
- });
30
-
31
- // INJECT:ROUTES
32
-
33
- app.use((req, res) => {
34
- res.status(404).json({ message: 'Route not found' });
35
- });
36
-
37
- app.use((err, req, res, _next) => {
38
- console.error(err);
39
- res.status(err?.statusCode || 500).json({
40
- message: err?.message || 'Internal Server Error',
41
- });
42
- });
43
-
44
- const PORT = process.env.PORT || 8000;
45
-
46
- const server = app.listen(PORT, () => {
47
- console.log(`Server running on http://localhost:${PORT}`);
48
- });
49
-
50
- function shutdown(signal) {
51
- console.log(`Received ${signal}. Shutting down...`);
52
- server.close(() => {
53
- console.log('HTTP server closed.');
54
- process.exit(0);
55
- });
56
- }
57
-
58
- process.on('SIGINT', () => shutdown('SIGINT'));
59
- process.on('SIGTERM', () => shutdown('SIGTERM'));
1
+ import express from 'express';
2
+ import cors from 'cors';
3
+ import dotenv from 'dotenv';
4
+ import helmet from 'helmet';
5
+ import morgan from 'morgan';
6
+
7
+ dotenv.config();
8
+
9
+ const app = express();
10
+
11
+ app.use(helmet());
12
+ app.use(morgan(process.env.NODE_ENV === 'production' ? 'combined' : 'dev'));
13
+
14
+ app.use(cors({
15
+ origin: process.env.CORS_ORIGIN
16
+ ? process.env.CORS_ORIGIN.split(',').map(s => s.trim())
17
+ : ['http://localhost:3000', 'http://localhost:5173'],
18
+ credentials: true,
19
+ }));
20
+
21
+ app.use(express.json({ limit: '1mb' }));
22
+
23
+ app.get('/api/health', (req, res) => {
24
+ res.status(200).json({ status: 'ok' });
25
+ });
26
+
27
+ app.get('/', (req, res) => {
28
+ res.send('Backend is running! Generated by create-backlist.');
29
+ });
30
+
31
+ // INJECT:ROUTES
32
+
33
+ app.use((req, res) => {
34
+ res.status(404).json({ message: 'Route not found' });
35
+ });
36
+
37
+ app.use((err, req, res, _next) => {
38
+ console.error(err);
39
+ res.status(err?.statusCode || 500).json({
40
+ message: err?.message || 'Internal Server Error',
41
+ });
42
+ });
43
+
44
+ const PORT = process.env.PORT || 8000;
45
+
46
+ const server = app.listen(PORT, () => {
47
+ console.log(`Server running on http://localhost:${PORT}`);
48
+ });
49
+
50
+ function shutdown(signal) {
51
+ console.log(`Received ${signal}. Shutting down...`);
52
+ server.close(() => {
53
+ console.log('HTTP server closed.');
54
+ process.exit(0);
55
+ });
56
+ }
57
+
58
+ process.on('SIGINT', () => shutdown('SIGINT'));
59
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
@@ -1,12 +1,12 @@
1
- FROM node:20-alpine
2
-
3
- WORKDIR /app
4
-
5
- COPY package*.json ./
6
- RUN npm ci --only=production
7
-
8
- COPY . .
9
-
10
- EXPOSE <%= port %>
11
-
12
- CMD ["node", "src/server.js"]
1
+ FROM node:20-alpine
2
+
3
+ WORKDIR /app
4
+
5
+ COPY package*.json ./
6
+ RUN npm ci --only=production
7
+
8
+ COPY . .
9
+
10
+ EXPOSE <%= port %>
11
+
12
+ CMD ["node", "src/server.js"]
@@ -1,66 +1,66 @@
1
- <% if (dbType === 'mongoose') { %>
2
- import User from '../models/User.model.js';
3
- <% } else { %>
4
- import { prisma } from '../db.js';
5
- <% } %>
6
- import bcrypt from 'bcryptjs';
7
- import jwt from 'jsonwebtoken';
8
-
9
- const JWT_SECRET = process.env.JWT_SECRET || 'changeme';
10
- const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '5h';
11
-
12
- export class AuthController {
13
-
14
- static async register(req, res) {
15
- try {
16
- const { name, email, password } = req.body;
17
- if (!email || !password) {
18
- return res.status(400).json({ message: 'Email and password are required' });
19
- }
20
-
21
- const hashedPassword = await bcrypt.hash(password, 12);
22
-
23
- <% if (dbType === 'mongoose') { %>
24
- const existing = await User.findOne({ email });
25
- if (existing) return res.status(409).json({ message: 'Email already in use' });
26
-
27
- const user = await User.create({ name, email, password: hashedPassword });
28
- const token = jwt.sign({ id: user._id, email: user.email }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });
29
- <% } else { %>
30
- const existing = await prisma.user.findUnique({ where: { email } });
31
- if (existing) return res.status(409).json({ message: 'Email already in use' });
32
-
33
- const user = await prisma.user.create({ data: { name, email, password: hashedPassword } });
34
- const token = jwt.sign({ id: user.id, email: user.email }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });
35
- <% } %>
36
-
37
- res.status(201).json({ token, user: { id: user.id || user._id, name: user.name, email: user.email } });
38
- } catch (error) {
39
- res.status(500).json({ message: error.message });
40
- }
41
- }
42
-
43
- static async login(req, res) {
44
- try {
45
- const { email, password } = req.body;
46
- if (!email || !password) {
47
- return res.status(400).json({ message: 'Email and password are required' });
48
- }
49
-
50
- <% if (dbType === 'mongoose') { %>
51
- const user = await User.findOne({ email });
52
- <% } else { %>
53
- const user = await prisma.user.findUnique({ where: { email } });
54
- <% } %>
55
- if (!user) return res.status(401).json({ message: 'Invalid credentials' });
56
-
57
- const isMatch = await bcrypt.compare(password, user.password);
58
- if (!isMatch) return res.status(401).json({ message: 'Invalid credentials' });
59
-
60
- const token = jwt.sign({ id: user.id || user._id, email: user.email }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });
61
- res.status(200).json({ token, user: { id: user.id || user._id, name: user.name, email: user.email } });
62
- } catch (error) {
63
- res.status(500).json({ message: error.message });
64
- }
65
- }
66
- }
1
+ <% if (dbType === 'mongoose') { %>
2
+ import User from '../models/User.model.js';
3
+ <% } else { %>
4
+ import { prisma } from '../db.js';
5
+ <% } %>
6
+ import bcrypt from 'bcryptjs';
7
+ import jwt from 'jsonwebtoken';
8
+
9
+ const JWT_SECRET = process.env.JWT_SECRET || 'changeme';
10
+ const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '5h';
11
+
12
+ export class AuthController {
13
+
14
+ static async register(req, res) {
15
+ try {
16
+ const { name, email, password } = req.body;
17
+ if (!email || !password) {
18
+ return res.status(400).json({ message: 'Email and password are required' });
19
+ }
20
+
21
+ const hashedPassword = await bcrypt.hash(password, 12);
22
+
23
+ <% if (dbType === 'mongoose') { %>
24
+ const existing = await User.findOne({ email });
25
+ if (existing) return res.status(409).json({ message: 'Email already in use' });
26
+
27
+ const user = await User.create({ name, email, password: hashedPassword });
28
+ const token = jwt.sign({ id: user._id, email: user.email }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });
29
+ <% } else { %>
30
+ const existing = await prisma.user.findUnique({ where: { email } });
31
+ if (existing) return res.status(409).json({ message: 'Email already in use' });
32
+
33
+ const user = await prisma.user.create({ data: { name, email, password: hashedPassword } });
34
+ const token = jwt.sign({ id: user.id, email: user.email }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });
35
+ <% } %>
36
+
37
+ res.status(201).json({ token, user: { id: user.id || user._id, name: user.name, email: user.email } });
38
+ } catch (error) {
39
+ res.status(500).json({ message: error.message });
40
+ }
41
+ }
42
+
43
+ static async login(req, res) {
44
+ try {
45
+ const { email, password } = req.body;
46
+ if (!email || !password) {
47
+ return res.status(400).json({ message: 'Email and password are required' });
48
+ }
49
+
50
+ <% if (dbType === 'mongoose') { %>
51
+ const user = await User.findOne({ email });
52
+ <% } else { %>
53
+ const user = await prisma.user.findUnique({ where: { email } });
54
+ <% } %>
55
+ if (!user) return res.status(401).json({ message: 'Invalid credentials' });
56
+
57
+ const isMatch = await bcrypt.compare(password, user.password);
58
+ if (!isMatch) return res.status(401).json({ message: 'Invalid credentials' });
59
+
60
+ const token = jwt.sign({ id: user.id || user._id, email: user.email }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });
61
+ res.status(200).json({ token, user: { id: user.id || user._id, name: user.name, email: user.email } });
62
+ } catch (error) {
63
+ res.status(500).json({ message: error.message });
64
+ }
65
+ }
66
+ }
@@ -1,19 +1,19 @@
1
- import jwt from 'jsonwebtoken';
2
-
3
- const JWT_SECRET = process.env.JWT_SECRET || 'changeme';
4
-
5
- export function authMiddleware(req, res, next) {
6
- const authHeader = req.headers.authorization;
7
- if (!authHeader || !authHeader.startsWith('Bearer ')) {
8
- return res.status(401).json({ message: 'Access denied. No token provided.' });
9
- }
10
-
11
- const token = authHeader.split(' ')[1];
12
- try {
13
- const decoded = jwt.verify(token, JWT_SECRET);
14
- req.user = decoded;
15
- next();
16
- } catch (error) {
17
- return res.status(401).json({ message: 'Invalid or expired token.' });
18
- }
19
- }
1
+ import jwt from 'jsonwebtoken';
2
+
3
+ const JWT_SECRET = process.env.JWT_SECRET || 'changeme';
4
+
5
+ export function authMiddleware(req, res, next) {
6
+ const authHeader = req.headers.authorization;
7
+ if (!authHeader || !authHeader.startsWith('Bearer ')) {
8
+ return res.status(401).json({ message: 'Access denied. No token provided.' });
9
+ }
10
+
11
+ const token = authHeader.split(' ')[1];
12
+ try {
13
+ const decoded = jwt.verify(token, JWT_SECRET);
14
+ req.user = decoded;
15
+ next();
16
+ } catch (error) {
17
+ return res.status(401).json({ message: 'Invalid or expired token.' });
18
+ }
19
+ }
@@ -1,9 +1,9 @@
1
- import { Router } from 'express';
2
- import { AuthController } from '../controllers/Auth.controller.js';
3
-
4
- const router = Router();
5
-
6
- router.post('/register', AuthController.register);
7
- router.post('/login', AuthController.login);
8
-
9
- export default router;
1
+ import { Router } from 'express';
2
+ import { AuthController } from '../controllers/Auth.controller.js';
3
+
4
+ const router = Router();
5
+
6
+ router.post('/register', AuthController.register);
7
+ router.post('/login', AuthController.login);
8
+
9
+ export default router;
@@ -1,53 +1,53 @@
1
- import { <%= modelName %>Service } from '../services/<%= modelName %>.service.js';
2
-
3
- export class <%= modelName %>Controller {
4
-
5
- static async getAll(req, res) {
6
- try {
7
- const data = await <%= modelName %>Service.getAll();
8
- res.status(200).json(data);
9
- } catch (error) {
10
- res.status(500).json({ message: error.message });
11
- }
12
- }
13
-
14
- static async getById(req, res) {
15
- try {
16
- const { id } = req.params;
17
- const data = await <%= modelName %>Service.getById(id);
18
- if (!data) return res.status(404).json({ message: 'Not found' });
19
- res.status(200).json(data);
20
- } catch (error) {
21
- res.status(500).json({ message: error.message });
22
- }
23
- }
24
-
25
- static async create(req, res) {
26
- try {
27
- const data = await <%= modelName %>Service.create(req.body);
28
- res.status(201).json(data);
29
- } catch (error) {
30
- res.status(400).json({ message: error.message });
31
- }
32
- }
33
-
34
- static async update(req, res) {
35
- try {
36
- const { id } = req.params;
37
- const data = await <%= modelName %>Service.update(id, req.body);
38
- res.status(200).json(data);
39
- } catch (error) {
40
- res.status(400).json({ message: error.message });
41
- }
42
- }
43
-
44
- static async delete(req, res) {
45
- try {
46
- const { id } = req.params;
47
- await <%= modelName %>Service.delete(id);
48
- res.status(204).send();
49
- } catch (error) {
50
- res.status(500).json({ message: error.message });
51
- }
52
- }
53
- }
1
+ import { <%= modelName %>Service } from '../services/<%= modelName %>.service.js';
2
+
3
+ export class <%= modelName %>Controller {
4
+
5
+ static async getAll(req, res) {
6
+ try {
7
+ const data = await <%= modelName %>Service.getAll();
8
+ res.status(200).json(data);
9
+ } catch (error) {
10
+ res.status(500).json({ message: error.message });
11
+ }
12
+ }
13
+
14
+ static async getById(req, res) {
15
+ try {
16
+ const { id } = req.params;
17
+ const data = await <%= modelName %>Service.getById(id);
18
+ if (!data) return res.status(404).json({ message: 'Not found' });
19
+ res.status(200).json(data);
20
+ } catch (error) {
21
+ res.status(500).json({ message: error.message });
22
+ }
23
+ }
24
+
25
+ static async create(req, res) {
26
+ try {
27
+ const data = await <%= modelName %>Service.create(req.body);
28
+ res.status(201).json(data);
29
+ } catch (error) {
30
+ res.status(400).json({ message: error.message });
31
+ }
32
+ }
33
+
34
+ static async update(req, res) {
35
+ try {
36
+ const { id } = req.params;
37
+ const data = await <%= modelName %>Service.update(id, req.body);
38
+ res.status(200).json(data);
39
+ } catch (error) {
40
+ res.status(400).json({ message: error.message });
41
+ }
42
+ }
43
+
44
+ static async delete(req, res) {
45
+ try {
46
+ const { id } = req.params;
47
+ await <%= modelName %>Service.delete(id);
48
+ res.status(204).send();
49
+ } catch (error) {
50
+ res.status(500).json({ message: error.message });
51
+ }
52
+ }
53
+ }
@@ -1,19 +1,19 @@
1
- <% if (dbType === 'prisma') { %>
2
- import { PrismaClient } from '@prisma/client';
3
-
4
- export const prisma = new PrismaClient();
5
- <% } else { %>
6
- import mongoose from 'mongoose';
7
-
8
- const MONGO_URI = process.env.MONGO_URI || 'mongodb://127.0.0.1:27017/<%= projectName %>';
9
-
10
- export async function connectDB() {
11
- try {
12
- await mongoose.connect(MONGO_URI);
13
- console.log('MongoDB Connected...');
14
- } catch (err) {
15
- console.error('MongoDB connection error:', err.message);
16
- process.exit(1);
17
- }
18
- }
19
- <% } %>
1
+ <% if (dbType === 'prisma') { %>
2
+ import { PrismaClient } from '@prisma/client';
3
+
4
+ export const prisma = new PrismaClient();
5
+ <% } else { %>
6
+ import mongoose from 'mongoose';
7
+
8
+ const MONGO_URI = process.env.MONGO_URI || 'mongodb://127.0.0.1:27017/<%= projectName %>';
9
+
10
+ export async function connectDB() {
11
+ try {
12
+ await mongoose.connect(MONGO_URI);
13
+ console.log('MongoDB Connected...');
14
+ } catch (err) {
15
+ console.error('MongoDB connection error:', err.message);
16
+ process.exit(1);
17
+ }
18
+ }
19
+ <% } %>