create-backlist 7.0.1 → 7.3.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.
Files changed (54) hide show
  1. package/README.md +1 -10
  2. package/bin/index.js +242 -275
  3. package/package.json +3 -2
  4. package/src/ai-agent.js +171 -171
  5. package/src/analyzer.js +750 -495
  6. package/src/env-resolver.js +70 -0
  7. package/src/generators/dotnet.js +134 -133
  8. package/src/generators/java.js +248 -233
  9. package/src/generators/js.js +346 -0
  10. package/src/generators/nestjs.js +278 -0
  11. package/src/generators/node.js +404 -404
  12. package/src/generators/python.js +86 -104
  13. package/src/generators/template.js +22 -22
  14. package/src/project-detector.js +131 -0
  15. package/src/templates/dotnet/partials/Dockerfile.ejs +27 -0
  16. package/src/templates/dotnet/partials/docker-compose.yml.ejs +33 -0
  17. package/src/templates/java-spring/partials/Controller.java.ejs +3 -3
  18. package/src/templates/js-express/base/server.js +59 -0
  19. package/src/templates/js-express/partials/Dockerfile.ejs +12 -0
  20. package/src/templates/js-express/partials/auth.controller.js.ejs +66 -0
  21. package/src/templates/js-express/partials/auth.middleware.js.ejs +19 -0
  22. package/src/templates/js-express/partials/auth.routes.js.ejs +9 -0
  23. package/src/templates/js-express/partials/controller.js.ejs +53 -0
  24. package/src/templates/js-express/partials/db.js.ejs +19 -0
  25. package/src/templates/js-express/partials/docker-compose.yml.ejs +46 -0
  26. package/src/templates/js-express/partials/model.js.ejs +18 -0
  27. package/src/templates/js-express/partials/package.json.ejs +17 -0
  28. package/src/templates/js-express/partials/prisma.schema.ejs +21 -0
  29. package/src/templates/js-express/partials/routes.js.ejs +19 -0
  30. package/src/templates/js-express/partials/seeder.js.ejs +103 -0
  31. package/src/templates/js-express/partials/service.js.ejs +51 -0
  32. package/src/templates/js-express/partials/swagger.js.ejs +30 -0
  33. package/src/templates/js-express/partials/test.js.ejs +46 -0
  34. package/src/templates/nestjs/base/app.module.ts +9 -0
  35. package/src/templates/nestjs/base/main.ts +23 -0
  36. package/src/templates/nestjs/base/tsconfig.json +21 -0
  37. package/src/templates/nestjs/partials/auth.controller.ts.ejs +17 -0
  38. package/src/templates/nestjs/partials/auth.module.ts.ejs +17 -0
  39. package/src/templates/nestjs/partials/auth.service.ts.ejs +70 -0
  40. package/src/templates/nestjs/partials/controller.ts.ejs +34 -0
  41. package/src/templates/nestjs/partials/create-dto.ts.ejs +22 -0
  42. package/src/templates/nestjs/partials/jwt-guard.ts.ejs +24 -0
  43. package/src/templates/nestjs/partials/module.ts.ejs +10 -0
  44. package/src/templates/nestjs/partials/package.json.ejs +27 -0
  45. package/src/templates/nestjs/partials/prisma.service.ts.ejs +13 -0
  46. package/src/templates/nestjs/partials/schema.ts.ejs +19 -0
  47. package/src/templates/nestjs/partials/service.ts.ejs +67 -0
  48. package/src/templates/nestjs/partials/update-dto.ts.ejs +4 -0
  49. package/src/templates/node-ts-express/partials/HexController.ts.ejs +56 -56
  50. package/src/templates/node-ts-express/partials/HexRepository.ts.ejs +26 -26
  51. package/src/templates/node-ts-express/partials/HexService.ts.ejs +27 -27
  52. package/src/utils.js +11 -11
  53. /package/src/templates/{node-ts-express → dotnet}/partials/DbContext.cs.ejs +0 -0
  54. /package/src/templates/{node-ts-express → dotnet}/partials/Model.cs.ejs +0 -0
@@ -0,0 +1,70 @@
1
+ import fs from "fs-extra";
2
+ import path from "node:path";
3
+
4
+ const ENV_FILES = [
5
+ ".env.local",
6
+ ".env.development",
7
+ ".env.development.local",
8
+ ".env",
9
+ ];
10
+
11
+ const API_URL_PATTERNS = [
12
+ "API_URL",
13
+ "API_BASE_URL",
14
+ "API_BASE",
15
+ "BASE_URL",
16
+ "BACKEND_URL",
17
+ "SERVER_URL",
18
+ ];
19
+
20
+ export async function parseEnvFiles(projectRoot) {
21
+ const envMap = new Map();
22
+
23
+ for (const envFile of ENV_FILES) {
24
+ const filePath = path.join(projectRoot, envFile);
25
+ if (!(await fs.pathExists(filePath))) continue;
26
+
27
+ let content;
28
+ try {
29
+ content = await fs.readFile(filePath, "utf-8");
30
+ } catch {
31
+ continue;
32
+ }
33
+
34
+ for (const line of content.split("\n")) {
35
+ const trimmed = line.trim();
36
+ if (!trimmed || trimmed.startsWith("#")) continue;
37
+
38
+ const eqIndex = trimmed.indexOf("=");
39
+ if (eqIndex === -1) continue;
40
+
41
+ const key = trimmed.slice(0, eqIndex).trim();
42
+ let value = trimmed.slice(eqIndex + 1).trim();
43
+
44
+ if (
45
+ (value.startsWith('"') && value.endsWith('"')) ||
46
+ (value.startsWith("'") && value.endsWith("'"))
47
+ ) {
48
+ value = value.slice(1, -1);
49
+ }
50
+
51
+ if (key && value && !envMap.has(key)) {
52
+ envMap.set(key, value);
53
+ }
54
+ }
55
+ }
56
+
57
+ return envMap;
58
+ }
59
+
60
+ export function extractBaseUrlFromEnv(envMap) {
61
+ for (const [key, value] of envMap) {
62
+ const upperKey = key.toUpperCase();
63
+ for (const pattern of API_URL_PATTERNS) {
64
+ if (upperKey.includes(pattern) && value.startsWith("http")) {
65
+ return value.replace(/\/$/, "");
66
+ }
67
+ }
68
+ }
69
+ return null;
70
+ }
@@ -1,133 +1,134 @@
1
- const chalk = require('chalk');
2
- const { execa } = require('execa');
3
- const fs = require('fs-extra');
4
- const path = require('path');
5
- const { analyzeFrontend } = require('../analyzer');
6
- const { renderAndWrite, getTemplatePath } = require('./template');
7
-
8
- async function generateDotnetProject(options) {
9
- const { projectDir, projectName, frontendSrcDir } = options;
10
-
11
- try {
12
- // --- Step 1: Analysis & Model Identification ---
13
- console.log(chalk.blue(' -> Analyzing frontend for C# backend...'));
14
- const endpoints = await analyzeFrontend(frontendSrcDir);
15
- const modelsToGenerate = new Map();
16
- endpoints.forEach(ep => {
17
- // For C#, we create a model if schemaFields exist for any endpoint related to a controller
18
- if (ep.schemaFields && ep.controllerName !== 'Default' && !modelsToGenerate.has(ep.controllerName)) {
19
- modelsToGenerate.set(ep.controllerName, {
20
- name: ep.controllerName,
21
- fields: Object.entries(ep.schemaFields).map(([key, type]) => ({ name: key, type }))
22
- });
23
- }
24
- });
25
-
26
- if (modelsToGenerate.size > 0) {
27
- console.log(chalk.green(` -> Identified ${modelsToGenerate.size} models/controllers to generate.`));
28
- } else {
29
- console.log(chalk.yellow(' -> No API calls with body data found. A basic API project will be created without models.'));
30
- }
31
-
32
- // --- Step 2: Create Base .NET Project using `dotnet new` ---
33
- console.log(chalk.blue(' -> Scaffolding .NET Core Web API project...'));
34
- await execa('dotnet', ['new', 'webapi', '-n', projectName, '-o', projectDir, '--no-https']);
35
-
36
- // --- Step 3: Add Required NuGet Packages ---
37
- if (modelsToGenerate.size > 0) {
38
- console.log(chalk.blue(' -> Adding NuGet packages (Entity Framework Core)...'));
39
- const packages = [
40
- 'Microsoft.EntityFrameworkCore.Design',
41
- 'Microsoft.EntityFrameworkCore.InMemory' // Using InMemory for a simple, runnable setup
42
- // For a real DB, a user would add: 'Npgsql.EntityFrameworkCore.PostgreSQL' or 'Microsoft.EntityFrameworkCore.SqlServer'
43
- ];
44
- for (const pkg of packages) {
45
- await execa('dotnet', ['add', 'package', pkg], { cwd: projectDir });
46
- }
47
- }
48
-
49
- // --- Step 4: Generate Models and DbContext from Templates ---
50
- if (modelsToGenerate.size > 0) {
51
- console.log(chalk.blue(' -> Generating EF Core models and DbContext...'));
52
- const modelsDir = path.join(projectDir, 'Models');
53
- const dataDir = path.join(projectDir, 'Data');
54
- await fs.ensureDir(modelsDir);
55
- await fs.ensureDir(dataDir);
56
-
57
- for (const [modelName, modelData] of modelsToGenerate.entries()) {
58
- await renderAndWrite(
59
- getTemplatePath('dotnet/partials/Model.cs.ejs'),
60
- path.join(modelsDir, `${modelName}.cs`),
61
- { projectName, modelName, model: modelData }
62
- );
63
- }
64
-
65
- await renderAndWrite(
66
- getTemplatePath('dotnet/partials/DbContext.cs.ejs'),
67
- path.join(dataDir, 'ApplicationDbContext.cs'),
68
- { projectName, modelsToGenerate: Array.from(modelsToGenerate.values()) }
69
- );
70
- }
71
-
72
- // --- Step 5: Configure Services in Program.cs ---
73
- console.log(chalk.blue(' -> Configuring services in Program.cs...'));
74
- const programCsPath = path.join(projectDir, 'Program.cs');
75
- let programCsContent = await fs.readFile(programCsPath, 'utf-8');
76
-
77
- let usingStatements = 'using Microsoft.EntityFrameworkCore;\nusing '+projectName+'.Data;\n';
78
- programCsContent = usingStatements + programCsContent;
79
-
80
- let dbContextService = '// Configure the database context\nbuilder.Services.AddDbContext<ApplicationDbContext>(opt => opt.UseInMemoryDatabase("MyDb"));';
81
- programCsContent = programCsContent.replace('builder.Services.AddControllers();', `builder.Services.AddControllers();\n\n${dbContextService}`);
82
-
83
- // Enable CORS to allow frontend communication
84
- const corsPolicy = `
85
- builder.Services.AddCors(options =>
86
- {
87
- options.AddDefaultPolicy(
88
- policy =>
89
- {
90
- policy.WithOrigins("http://localhost:3000", "http://localhost:5173") // Common frontend dev ports
91
- .AllowAnyHeader()
92
- .AllowAnyMethod();
93
- });
94
- });`;
95
- programCsContent = programCsContent.replace('var app = builder.Build();', `${corsPolicy}\n\nvar app = builder.Build();\n\napp.UseCors();`);
96
-
97
- await fs.writeFile(programCsPath, programCsContent);
98
-
99
- // --- Step 6: Generate Controllers with full CRUD ---
100
- console.log(chalk.blue(' -> Generating controllers with CRUD logic...'));
101
- await fs.remove(path.join(projectDir, 'Controllers', 'WeatherForecastController.cs'));
102
- await fs.remove(path.join(projectDir, 'WeatherForecast.cs'));
103
-
104
- const controllersToGenerate = new Set(Array.from(modelsToGenerate.keys()));
105
- // Also add controllers for endpoints that didn't have a body but were detected
106
- endpoints.forEach(ep => {
107
- if (ep.controllerName !== 'Default') controllersToGenerate.add(ep.controllerName);
108
- });
109
-
110
- for (const controllerName of controllersToGenerate) {
111
- await renderAndWrite(
112
- getTemplatePath('dotnet/partials/Controller.cs.ejs'),
113
- path.join(projectDir, 'Controllers', `${controllerName}Controller.cs`),
114
- { projectName, controllerName }
115
- );
116
- }
117
-
118
- // --- Step 7: Generate README ---
119
- await renderAndWrite(
120
- getTemplatePath('dotnet/partials/README.md.ejs'),
121
- path.join(projectDir, 'README.md'),
122
- { projectName }
123
- );
124
-
125
- console.log(chalk.green(' -> C# backend generation is complete!'));
126
-
127
- } catch (error) {
128
- // Re-throw the error to be caught by the main CLI handler
129
- throw error;
130
- }
131
- }
132
-
133
- module.exports = { generateDotnetProject };
1
+ import chalk from 'chalk';
2
+ import { execa } from 'execa';
3
+ import fs from 'fs-extra';
4
+ import path from 'node:path';
5
+ import { analyzeFrontend } from '../analyzer.js';
6
+ import { renderAndWrite, getTemplatePath } from './template.js';
7
+
8
+ export async function generateDotnetProject(options) {
9
+ const { projectDir, projectName, frontendSrcDir } = options;
10
+
11
+ try {
12
+ console.log(chalk.blue(' -> Analyzing frontend for C# backend...'));
13
+ const endpoints = await analyzeFrontend(frontendSrcDir);
14
+ const modelsToGenerate = new Map();
15
+ endpoints.forEach(ep => {
16
+ if (ep.schemaFields && ep.controllerName !== 'Default' && !modelsToGenerate.has(ep.controllerName)) {
17
+ modelsToGenerate.set(ep.controllerName, {
18
+ name: ep.controllerName,
19
+ fields: Object.entries(ep.schemaFields).map(([key, type]) => ({ name: key, type }))
20
+ });
21
+ }
22
+ });
23
+
24
+ if (modelsToGenerate.size > 0) {
25
+ console.log(chalk.green(` -> Identified ${modelsToGenerate.size} models/controllers to generate.`));
26
+ } else {
27
+ console.log(chalk.yellow(' -> No API calls with body data found. A basic API project will be created without models.'));
28
+ }
29
+
30
+ console.log(chalk.blue(' -> Scaffolding .NET Core Web API project...'));
31
+ await execa('dotnet', ['new', 'webapi', '-n', projectName, '-o', projectDir, '--no-https']);
32
+
33
+ if (modelsToGenerate.size > 0) {
34
+ console.log(chalk.blue(' -> Adding NuGet packages (Entity Framework Core)...'));
35
+ const packages = [
36
+ 'Microsoft.EntityFrameworkCore.Design',
37
+ 'Microsoft.EntityFrameworkCore.InMemory'
38
+ ];
39
+ for (const pkg of packages) {
40
+ await execa('dotnet', ['add', 'package', pkg], { cwd: projectDir });
41
+ }
42
+ }
43
+
44
+ if (modelsToGenerate.size > 0) {
45
+ console.log(chalk.blue(' -> Generating EF Core models and DbContext...'));
46
+ const modelsDir = path.join(projectDir, 'Models');
47
+ const dataDir = path.join(projectDir, 'Data');
48
+ await fs.ensureDir(modelsDir);
49
+ await fs.ensureDir(dataDir);
50
+
51
+ for (const [modelName, modelData] of modelsToGenerate.entries()) {
52
+ await renderAndWrite(
53
+ getTemplatePath('dotnet/partials/Model.cs.ejs'),
54
+ path.join(modelsDir, `${modelName}.cs`),
55
+ { projectName, modelName, model: modelData }
56
+ );
57
+ }
58
+
59
+ await renderAndWrite(
60
+ getTemplatePath('dotnet/partials/DbContext.cs.ejs'),
61
+ path.join(dataDir, 'ApplicationDbContext.cs'),
62
+ { projectName, modelsToGenerate: Array.from(modelsToGenerate.values()) }
63
+ );
64
+ }
65
+
66
+ console.log(chalk.blue(' -> Configuring services in Program.cs...'));
67
+ const programCsPath = path.join(projectDir, 'Program.cs');
68
+ let programCsContent = await fs.readFile(programCsPath, 'utf-8');
69
+
70
+ let usingStatements = 'using Microsoft.EntityFrameworkCore;\nusing ' + projectName + '.Data;\n';
71
+ programCsContent = usingStatements + programCsContent;
72
+
73
+ let dbContextService = '// Configure the database context\nbuilder.Services.AddDbContext<ApplicationDbContext>(opt => opt.UseInMemoryDatabase("MyDb"));';
74
+ programCsContent = programCsContent.replace('builder.Services.AddControllers();', `builder.Services.AddControllers();\n\n${dbContextService}`);
75
+
76
+ const corsPolicy = `
77
+ builder.Services.AddCors(options =>
78
+ {
79
+ options.AddDefaultPolicy(
80
+ policy =>
81
+ {
82
+ policy.WithOrigins("http://localhost:3000", "http://localhost:5173")
83
+ .AllowAnyHeader()
84
+ .AllowAnyMethod();
85
+ });
86
+ });`;
87
+ programCsContent = programCsContent.replace('var app = builder.Build();', `${corsPolicy}\n\nvar app = builder.Build();\n\napp.UseCors();`);
88
+
89
+ await fs.writeFile(programCsPath, programCsContent);
90
+
91
+ console.log(chalk.blue(' -> Generating controllers with CRUD logic...'));
92
+ await fs.remove(path.join(projectDir, 'Controllers', 'WeatherForecastController.cs'));
93
+ await fs.remove(path.join(projectDir, 'WeatherForecast.cs'));
94
+
95
+ const controllersToGenerate = new Set(Array.from(modelsToGenerate.keys()));
96
+ endpoints.forEach(ep => {
97
+ if (ep.controllerName !== 'Default') controllersToGenerate.add(ep.controllerName);
98
+ });
99
+
100
+ for (const controllerName of controllersToGenerate) {
101
+ const controllerEndpoints = endpoints.filter(
102
+ ep => ep.controllerName === controllerName
103
+ );
104
+ await renderAndWrite(
105
+ getTemplatePath('dotnet/partials/Controller.cs.ejs'),
106
+ path.join(projectDir, 'Controllers', `${controllerName}Controller.cs`),
107
+ { projectName, controllerName, endpoints: controllerEndpoints }
108
+ );
109
+ }
110
+
111
+ console.log(chalk.blue(' -> Generating Docker files...'));
112
+ await renderAndWrite(
113
+ getTemplatePath('dotnet/partials/Dockerfile.ejs'),
114
+ path.join(projectDir, 'Dockerfile'),
115
+ { projectName }
116
+ );
117
+ await renderAndWrite(
118
+ getTemplatePath('dotnet/partials/docker-compose.yml.ejs'),
119
+ path.join(projectDir, 'docker-compose.yml'),
120
+ { projectName }
121
+ );
122
+
123
+ await renderAndWrite(
124
+ getTemplatePath('dotnet/partials/README.md.ejs'),
125
+ path.join(projectDir, 'README.md'),
126
+ { projectName }
127
+ );
128
+
129
+ console.log(chalk.green(' -> C# backend generation is complete!'));
130
+
131
+ } catch (error) {
132
+ throw error;
133
+ }
134
+ }