stackforge-cli 0.1.2__py3-none-any.whl → 0.1.4__py3-none-any.whl
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.
- stackforge/engines/dotnet/__init__.py +7 -7
- stackforge/engines/dotnet/api_generator.py +313 -312
- stackforge/engines/dotnet/config_generator.py +76 -76
- stackforge/engines/dotnet/csproj_generator.py +82 -82
- stackforge/engines/dotnet/docker_generator.py +63 -63
- stackforge/engines/dotnet/git_generator.py +126 -111
- stackforge/engines/dotnet/layers_generator.py +543 -543
- stackforge/engines/dotnet/program_generator.py +245 -195
- stackforge/engines/dotnet/scaffolder.py +74 -74
- stackforge/project_name.py +34 -34
- stackforge/scaffold.py +90 -80
- stackforge/ui.py +72 -72
- stackforge/version.py +48 -48
- {stackforge_cli-0.1.2.dist-info → stackforge_cli-0.1.4.dist-info}/METADATA +107 -107
- stackforge_cli-0.1.4.dist-info/RECORD +19 -0
- {stackforge_cli-0.1.2.dist-info → stackforge_cli-0.1.4.dist-info}/WHEEL +1 -1
- stackforge_cli-0.1.2.dist-info/RECORD +0 -19
- {stackforge_cli-0.1.2.dist-info → stackforge_cli-0.1.4.dist-info}/entry_points.txt +0 -0
- {stackforge_cli-0.1.2.dist-info → stackforge_cli-0.1.4.dist-info}/top_level.txt +0 -0
|
@@ -1,195 +1,245 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
from stackforge import ui
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def generate_configure_services(layer: str, base: Path, project: str):
|
|
6
|
-
templates = {
|
|
7
|
-
"Application": f"""using FluentValidation;
|
|
8
|
-
using MediatR;
|
|
9
|
-
using Microsoft.Extensions.DependencyInjection;
|
|
10
|
-
using System.Reflection;
|
|
11
|
-
|
|
12
|
-
namespace {project}.Application
|
|
13
|
-
{{
|
|
14
|
-
public static class ConfigureServices
|
|
15
|
-
{{
|
|
16
|
-
public static IServiceCollection AddApplicationServices(this IServiceCollection services)
|
|
17
|
-
{{
|
|
18
|
-
services.AddMediatR(cfg =>
|
|
19
|
-
cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));
|
|
20
|
-
|
|
21
|
-
services.AddAutoMapper(cfg => cfg.AddMaps(Assembly.GetExecutingAssembly()));
|
|
22
|
-
|
|
23
|
-
services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
|
|
24
|
-
|
|
25
|
-
return services;
|
|
26
|
-
}}
|
|
27
|
-
}}
|
|
28
|
-
}}
|
|
29
|
-
""",
|
|
30
|
-
"Infrastructure": f"""using Microsoft.Extensions.DependencyInjection;
|
|
31
|
-
|
|
32
|
-
namespace {project}.Infrastructure
|
|
33
|
-
{{
|
|
34
|
-
public static class ConfigureServices
|
|
35
|
-
{{
|
|
36
|
-
public static IServiceCollection AddInfrastructureServices(this IServiceCollection services)
|
|
37
|
-
{{
|
|
38
|
-
// Register infrastructure services here
|
|
39
|
-
|
|
40
|
-
return services;
|
|
41
|
-
}}
|
|
42
|
-
}}
|
|
43
|
-
}}
|
|
44
|
-
""",
|
|
45
|
-
"Persistence": f"""using {project}.Persistence;
|
|
46
|
-
using Microsoft.EntityFrameworkCore;
|
|
47
|
-
using Microsoft.Extensions.Configuration;
|
|
48
|
-
using Microsoft.Extensions.DependencyInjection;
|
|
49
|
-
|
|
50
|
-
namespace {project}.Persistence
|
|
51
|
-
{{
|
|
52
|
-
public static class ConfigureServices
|
|
53
|
-
{{
|
|
54
|
-
public static IServiceCollection AddPersistenceServices(this IServiceCollection services, IConfiguration configuration)
|
|
55
|
-
{{
|
|
56
|
-
services.AddDbContext<DataContext>(options =>
|
|
57
|
-
options.UseNpgsql(configuration.GetConnectionString("DefaultConnection")));
|
|
58
|
-
|
|
59
|
-
return services;
|
|
60
|
-
}}
|
|
61
|
-
}}
|
|
62
|
-
}}
|
|
63
|
-
""",
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}}
|
|
117
|
-
.
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from stackforge import ui
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def generate_configure_services(layer: str, base: Path, project: str):
|
|
6
|
+
templates = {
|
|
7
|
+
"Application": f"""using FluentValidation;
|
|
8
|
+
using MediatR;
|
|
9
|
+
using Microsoft.Extensions.DependencyInjection;
|
|
10
|
+
using System.Reflection;
|
|
11
|
+
|
|
12
|
+
namespace {project}.Application
|
|
13
|
+
{{
|
|
14
|
+
public static class ConfigureServices
|
|
15
|
+
{{
|
|
16
|
+
public static IServiceCollection AddApplicationServices(this IServiceCollection services)
|
|
17
|
+
{{
|
|
18
|
+
services.AddMediatR(cfg =>
|
|
19
|
+
cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));
|
|
20
|
+
|
|
21
|
+
services.AddAutoMapper(cfg => cfg.AddMaps(Assembly.GetExecutingAssembly()));
|
|
22
|
+
|
|
23
|
+
services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
|
|
24
|
+
|
|
25
|
+
return services;
|
|
26
|
+
}}
|
|
27
|
+
}}
|
|
28
|
+
}}
|
|
29
|
+
""",
|
|
30
|
+
"Infrastructure": f"""using Microsoft.Extensions.DependencyInjection;
|
|
31
|
+
|
|
32
|
+
namespace {project}.Infrastructure
|
|
33
|
+
{{
|
|
34
|
+
public static class ConfigureServices
|
|
35
|
+
{{
|
|
36
|
+
public static IServiceCollection AddInfrastructureServices(this IServiceCollection services)
|
|
37
|
+
{{
|
|
38
|
+
// Register infrastructure services here
|
|
39
|
+
|
|
40
|
+
return services;
|
|
41
|
+
}}
|
|
42
|
+
}}
|
|
43
|
+
}}
|
|
44
|
+
""",
|
|
45
|
+
"Persistence": f"""using {project}.Persistence;
|
|
46
|
+
using Microsoft.EntityFrameworkCore;
|
|
47
|
+
using Microsoft.Extensions.Configuration;
|
|
48
|
+
using Microsoft.Extensions.DependencyInjection;
|
|
49
|
+
|
|
50
|
+
namespace {project}.Persistence
|
|
51
|
+
{{
|
|
52
|
+
public static class ConfigureServices
|
|
53
|
+
{{
|
|
54
|
+
public static IServiceCollection AddPersistenceServices(this IServiceCollection services, IConfiguration configuration)
|
|
55
|
+
{{
|
|
56
|
+
services.AddDbContext<DataContext>(options =>
|
|
57
|
+
options.UseNpgsql(configuration.GetConnectionString("DefaultConnection")));
|
|
58
|
+
|
|
59
|
+
return services;
|
|
60
|
+
}}
|
|
61
|
+
}}
|
|
62
|
+
}}
|
|
63
|
+
""",
|
|
64
|
+
"API": f"""using {project}.API.Interface;
|
|
65
|
+
using {project}.API.Options;
|
|
66
|
+
using {project}.API.Services;
|
|
67
|
+
using {project}.Domain.Entities.Identity;
|
|
68
|
+
using {project}.Persistence;
|
|
69
|
+
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
70
|
+
using Microsoft.AspNetCore.Authorization;
|
|
71
|
+
using Microsoft.AspNetCore.Identity;
|
|
72
|
+
using Microsoft.IdentityModel.Tokens;
|
|
73
|
+
using Microsoft.OpenApi.Models;
|
|
74
|
+
using System.Text;
|
|
75
|
+
using System.Text.Json.Serialization;
|
|
76
|
+
|
|
77
|
+
namespace {project}.API
|
|
78
|
+
{{
|
|
79
|
+
public static class ConfigureServices
|
|
80
|
+
{{
|
|
81
|
+
public const string CorsPolicy = "Cors";
|
|
82
|
+
|
|
83
|
+
public static IServiceCollection AddApiServices(this IServiceCollection services, IConfiguration configuration)
|
|
84
|
+
{{
|
|
85
|
+
services.Configure<JwtOptions>(configuration.GetSection("Jwt"));
|
|
86
|
+
var jwtOptions = new JwtOptions();
|
|
87
|
+
configuration.GetSection("Jwt").Bind(jwtOptions);
|
|
88
|
+
|
|
89
|
+
services.AddControllers()
|
|
90
|
+
.AddJsonOptions(options => options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));
|
|
91
|
+
|
|
92
|
+
services.AddEndpointsApiExplorer();
|
|
93
|
+
|
|
94
|
+
services.AddSwaggerGen(config =>
|
|
95
|
+
{{
|
|
96
|
+
config.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
|
97
|
+
{{
|
|
98
|
+
Name = "Authorization",
|
|
99
|
+
Type = SecuritySchemeType.Http,
|
|
100
|
+
Scheme = "bearer",
|
|
101
|
+
BearerFormat = "JWT",
|
|
102
|
+
In = ParameterLocation.Header,
|
|
103
|
+
Description = "Enter your JWT token only (no 'Bearer' prefix needed)"
|
|
104
|
+
}});
|
|
105
|
+
|
|
106
|
+
config.AddSecurityRequirement(new OpenApiSecurityRequirement
|
|
107
|
+
{{
|
|
108
|
+
{{
|
|
109
|
+
new OpenApiSecurityScheme
|
|
110
|
+
{{
|
|
111
|
+
Reference = new OpenApiReference
|
|
112
|
+
{{
|
|
113
|
+
Type = ReferenceType.SecurityScheme,
|
|
114
|
+
Id = "Bearer"
|
|
115
|
+
}}
|
|
116
|
+
}},
|
|
117
|
+
Array.Empty<string>()
|
|
118
|
+
}}
|
|
119
|
+
}});
|
|
120
|
+
}});
|
|
121
|
+
|
|
122
|
+
// Browser origins allowed to call the API. Format: scheme + host (+ port if non-default), no trailing slash.
|
|
123
|
+
// Only add frontends you own: an allowed origin's scripts can call this API from a visitor's browser.
|
|
124
|
+
// Bearer tokens travel in the Authorization header, so credentials (cookies) are not allowed.
|
|
125
|
+
services.AddCors(options =>
|
|
126
|
+
{{
|
|
127
|
+
options.AddPolicy(CorsPolicy, policy =>
|
|
128
|
+
{{
|
|
129
|
+
policy.AllowAnyMethod()
|
|
130
|
+
.AllowAnyHeader()
|
|
131
|
+
.WithExposedHeaders("WWW-Authenticate", "Retry-After")
|
|
132
|
+
.WithOrigins(
|
|
133
|
+
"http://localhost:3000"
|
|
134
|
+
);
|
|
135
|
+
}});
|
|
136
|
+
}});
|
|
137
|
+
|
|
138
|
+
services.AddIdentity<User, Role>(options =>
|
|
139
|
+
{{
|
|
140
|
+
options.Password.RequireDigit = true;
|
|
141
|
+
options.Password.RequireLowercase = true;
|
|
142
|
+
options.Password.RequireUppercase = true;
|
|
143
|
+
options.Password.RequireNonAlphanumeric = true;
|
|
144
|
+
options.Password.RequiredLength = 8;
|
|
145
|
+
}})
|
|
146
|
+
.AddEntityFrameworkStores<DataContext>()
|
|
147
|
+
.AddDefaultTokenProviders();
|
|
148
|
+
|
|
149
|
+
services.AddAuthentication(options =>
|
|
150
|
+
{{
|
|
151
|
+
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
152
|
+
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
153
|
+
}})
|
|
154
|
+
.AddJwtBearer(options =>
|
|
155
|
+
{{
|
|
156
|
+
options.TokenValidationParameters = new TokenValidationParameters
|
|
157
|
+
{{
|
|
158
|
+
ValidateIssuer = true,
|
|
159
|
+
ValidateAudience = true,
|
|
160
|
+
ValidateLifetime = true,
|
|
161
|
+
ValidateIssuerSigningKey = true,
|
|
162
|
+
ValidIssuer = jwtOptions.Issuer,
|
|
163
|
+
ValidAudience = jwtOptions.Audience,
|
|
164
|
+
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SecretKey))
|
|
165
|
+
}};
|
|
166
|
+
}});
|
|
167
|
+
|
|
168
|
+
// Deny by default: endpoints without an explicit policy require an authenticated user.
|
|
169
|
+
// Public endpoints must opt out with [AllowAnonymous].
|
|
170
|
+
services.AddAuthorization(options =>
|
|
171
|
+
{{
|
|
172
|
+
options.FallbackPolicy = new AuthorizationPolicyBuilder()
|
|
173
|
+
.RequireAuthenticatedUser()
|
|
174
|
+
.Build();
|
|
175
|
+
}});
|
|
176
|
+
|
|
177
|
+
//Scopes
|
|
178
|
+
services.AddScoped<IJwtService, JwtService>();
|
|
179
|
+
|
|
180
|
+
return services;
|
|
181
|
+
}}
|
|
182
|
+
}}
|
|
183
|
+
}}
|
|
184
|
+
""",
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if layer not in templates:
|
|
188
|
+
return
|
|
189
|
+
|
|
190
|
+
file_path = base / layer / "ConfigureServices.cs"
|
|
191
|
+
file_path.write_text(templates[layer])
|
|
192
|
+
ui.file_created(f"{layer}/ConfigureServices.cs")
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def generate_program_cs(base: Path, project: str):
|
|
196
|
+
content = f"""using {project}.API;
|
|
197
|
+
using {project}.Application;
|
|
198
|
+
using {project}.Domain.Entities.Identity;
|
|
199
|
+
using {project}.Infrastructure;
|
|
200
|
+
using {project}.Persistence;
|
|
201
|
+
using Microsoft.AspNetCore.Identity;
|
|
202
|
+
|
|
203
|
+
var builder = WebApplication.CreateBuilder(args);
|
|
204
|
+
|
|
205
|
+
// Layer services
|
|
206
|
+
builder.Services.AddApplicationServices();
|
|
207
|
+
builder.Services.AddInfrastructureServices();
|
|
208
|
+
builder.Services.AddPersistenceServices(builder.Configuration);
|
|
209
|
+
builder.Services.AddApiServices(builder.Configuration);
|
|
210
|
+
|
|
211
|
+
var app = builder.Build();
|
|
212
|
+
|
|
213
|
+
if (app.Environment.IsDevelopment())
|
|
214
|
+
{{
|
|
215
|
+
app.UseSwagger();
|
|
216
|
+
app.UseSwaggerUI();
|
|
217
|
+
}}
|
|
218
|
+
|
|
219
|
+
if (!app.Environment.IsDevelopment())
|
|
220
|
+
{{
|
|
221
|
+
app.UseHttpsRedirection();
|
|
222
|
+
}}
|
|
223
|
+
app.UseRouting();
|
|
224
|
+
app.UseCors({project}.API.ConfigureServices.CorsPolicy);
|
|
225
|
+
app.UseAuthentication();
|
|
226
|
+
app.UseAuthorization();
|
|
227
|
+
app.MapControllers();
|
|
228
|
+
|
|
229
|
+
using (var scope = app.Services.CreateScope())
|
|
230
|
+
{{
|
|
231
|
+
var db = scope.ServiceProvider.GetRequiredService<DataContext>();
|
|
232
|
+
db.Database.EnsureCreated();
|
|
233
|
+
|
|
234
|
+
var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<Role>>();
|
|
235
|
+
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<User>>();
|
|
236
|
+
await {project}.Persistence.Seeders.RoleSeeder.SeedAsync(roleManager);
|
|
237
|
+
await {project}.Persistence.Seeders.UserSeeder.SeedAsync(userManager);
|
|
238
|
+
}}
|
|
239
|
+
|
|
240
|
+
app.Run();
|
|
241
|
+
"""
|
|
242
|
+
|
|
243
|
+
file_path = base / "API" / "Program.cs"
|
|
244
|
+
file_path.write_text(content)
|
|
245
|
+
ui.file_created("API/Program.cs")
|
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
from stackforge import ui
|
|
3
|
-
from .csproj_generator import generate_csproj
|
|
4
|
-
from .program_generator import generate_configure_services, generate_program_cs
|
|
5
|
-
from .docker_generator import generate_dockerfile, generate_docker_compose
|
|
6
|
-
from .config_generator import generate_env, generate_appsettings, generate_appsettings_development
|
|
7
|
-
from .git_generator import generate_gitignore, generate_github_workflow, generate_sln, git_init
|
|
8
|
-
from .api_generator import generate_api_structure
|
|
9
|
-
from .layers_generator import (
|
|
10
|
-
generate_application_layer,
|
|
11
|
-
generate_domain_layer,
|
|
12
|
-
generate_infrastructure_layer,
|
|
13
|
-
generate_persistence_layer,
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
def scaffold_folders(base: Path, project: str):
|
|
17
|
-
layers = [
|
|
18
|
-
"API",
|
|
19
|
-
"Application",
|
|
20
|
-
"Domain",
|
|
21
|
-
"Infrastructure",
|
|
22
|
-
"Persistence"
|
|
23
|
-
]
|
|
24
|
-
|
|
25
|
-
ui.section(f"Scaffolding '{project}'")
|
|
26
|
-
|
|
27
|
-
ui.step("Creating folders")
|
|
28
|
-
for layer in layers:
|
|
29
|
-
folder = base / layer
|
|
30
|
-
folder.mkdir(parents=True, exist_ok=True)
|
|
31
|
-
ui.file_created(layer)
|
|
32
|
-
|
|
33
|
-
ui.section("Generating .csproj files")
|
|
34
|
-
for layer in layers:
|
|
35
|
-
generate_csproj(layer, base)
|
|
36
|
-
|
|
37
|
-
ui.section("Generating service registrations")
|
|
38
|
-
for layer in ["Application", "Infrastructure", "Persistence"]:
|
|
39
|
-
generate_configure_services(layer, base, project)
|
|
40
|
-
|
|
41
|
-
ui.section("Generating Program.cs")
|
|
42
|
-
generate_program_cs(base, project)
|
|
43
|
-
|
|
44
|
-
ui.section("Generating Docker files")
|
|
45
|
-
generate_dockerfile(base)
|
|
46
|
-
generate_docker_compose(base, project)
|
|
47
|
-
|
|
48
|
-
ui.section("Generating config files")
|
|
49
|
-
generate_env(base, project)
|
|
50
|
-
generate_appsettings(base, project)
|
|
51
|
-
generate_appsettings_development(base, project)
|
|
52
|
-
|
|
53
|
-
ui.section("Generating API layer")
|
|
54
|
-
generate_api_structure(base, project)
|
|
55
|
-
|
|
56
|
-
ui.section("Generating layer files")
|
|
57
|
-
generate_application_layer(base, project)
|
|
58
|
-
generate_domain_layer(base, project)
|
|
59
|
-
generate_infrastructure_layer(base, project)
|
|
60
|
-
generate_persistence_layer(base, project)
|
|
61
|
-
|
|
62
|
-
ui.section("Generating solution file")
|
|
63
|
-
generate_sln(base, project)
|
|
64
|
-
|
|
65
|
-
ui.section("Generating .gitignore")
|
|
66
|
-
generate_gitignore(base)
|
|
67
|
-
|
|
68
|
-
ui.section("Generating GitHub workflow")
|
|
69
|
-
generate_github_workflow(base)
|
|
70
|
-
|
|
71
|
-
ui.section("Initializing Git repository")
|
|
72
|
-
git_init(base, project)
|
|
73
|
-
|
|
74
|
-
ui.done()
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from stackforge import ui
|
|
3
|
+
from .csproj_generator import generate_csproj
|
|
4
|
+
from .program_generator import generate_configure_services, generate_program_cs
|
|
5
|
+
from .docker_generator import generate_dockerfile, generate_docker_compose
|
|
6
|
+
from .config_generator import generate_env, generate_appsettings, generate_appsettings_development
|
|
7
|
+
from .git_generator import generate_gitignore, generate_github_workflow, generate_sln, git_init
|
|
8
|
+
from .api_generator import generate_api_structure
|
|
9
|
+
from .layers_generator import (
|
|
10
|
+
generate_application_layer,
|
|
11
|
+
generate_domain_layer,
|
|
12
|
+
generate_infrastructure_layer,
|
|
13
|
+
generate_persistence_layer,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
def scaffold_folders(base: Path, project: str):
|
|
17
|
+
layers = [
|
|
18
|
+
"API",
|
|
19
|
+
"Application",
|
|
20
|
+
"Domain",
|
|
21
|
+
"Infrastructure",
|
|
22
|
+
"Persistence"
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
ui.section(f"Scaffolding '{project}'")
|
|
26
|
+
|
|
27
|
+
ui.step("Creating folders")
|
|
28
|
+
for layer in layers:
|
|
29
|
+
folder = base / layer
|
|
30
|
+
folder.mkdir(parents=True, exist_ok=True)
|
|
31
|
+
ui.file_created(layer)
|
|
32
|
+
|
|
33
|
+
ui.section("Generating .csproj files")
|
|
34
|
+
for layer in layers:
|
|
35
|
+
generate_csproj(layer, base)
|
|
36
|
+
|
|
37
|
+
ui.section("Generating service registrations")
|
|
38
|
+
for layer in ["Application", "Infrastructure", "Persistence", "API"]:
|
|
39
|
+
generate_configure_services(layer, base, project)
|
|
40
|
+
|
|
41
|
+
ui.section("Generating Program.cs")
|
|
42
|
+
generate_program_cs(base, project)
|
|
43
|
+
|
|
44
|
+
ui.section("Generating Docker files")
|
|
45
|
+
generate_dockerfile(base)
|
|
46
|
+
generate_docker_compose(base, project)
|
|
47
|
+
|
|
48
|
+
ui.section("Generating config files")
|
|
49
|
+
generate_env(base, project)
|
|
50
|
+
generate_appsettings(base, project)
|
|
51
|
+
generate_appsettings_development(base, project)
|
|
52
|
+
|
|
53
|
+
ui.section("Generating API layer")
|
|
54
|
+
generate_api_structure(base, project)
|
|
55
|
+
|
|
56
|
+
ui.section("Generating layer files")
|
|
57
|
+
generate_application_layer(base, project)
|
|
58
|
+
generate_domain_layer(base, project)
|
|
59
|
+
generate_infrastructure_layer(base, project)
|
|
60
|
+
generate_persistence_layer(base, project)
|
|
61
|
+
|
|
62
|
+
ui.section("Generating solution file")
|
|
63
|
+
generate_sln(base, project)
|
|
64
|
+
|
|
65
|
+
ui.section("Generating .gitignore")
|
|
66
|
+
generate_gitignore(base)
|
|
67
|
+
|
|
68
|
+
ui.section("Generating GitHub workflow")
|
|
69
|
+
generate_github_workflow(base)
|
|
70
|
+
|
|
71
|
+
ui.section("Initializing Git repository")
|
|
72
|
+
git_init(base, project)
|
|
73
|
+
|
|
74
|
+
ui.done()
|
stackforge/project_name.py
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
import re
|
|
2
|
-
|
|
3
|
-
_CAMEL_PARTS = re.compile(r"[A-Z]?[a-z]+|[A-Z]+(?=[A-Z][a-z]|\b)|\d+")
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def is_valid_project_name(name: str) -> bool:
|
|
7
|
-
if not name or not name[0].isalpha():
|
|
8
|
-
return False
|
|
9
|
-
if not re.fullmatch(r"[A-Za-z0-9_-]+", name):
|
|
10
|
-
return False
|
|
11
|
-
if name.startswith(("-", "_")) or name.endswith(("-", "_")):
|
|
12
|
-
return False
|
|
13
|
-
if "__" in name or "--" in name:
|
|
14
|
-
return False
|
|
15
|
-
return True
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def _title_part(part: str) -> str:
|
|
19
|
-
if not part:
|
|
20
|
-
return ""
|
|
21
|
-
if part.isdigit():
|
|
22
|
-
return part
|
|
23
|
-
return part[0].upper() + part[1:]
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def to_pascal_case(name: str) -> str:
|
|
27
|
-
if "_" in name:
|
|
28
|
-
parts = name.split("_")
|
|
29
|
-
elif "-" in name:
|
|
30
|
-
parts = name.split("-")
|
|
31
|
-
else:
|
|
32
|
-
parts = _CAMEL_PARTS.findall(name) or [name]
|
|
33
|
-
|
|
34
|
-
return "".join(_title_part(part) for part in parts if part)
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
_CAMEL_PARTS = re.compile(r"[A-Z]?[a-z]+|[A-Z]+(?=[A-Z][a-z]|\b)|\d+")
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def is_valid_project_name(name: str) -> bool:
|
|
7
|
+
if not name or not name[0].isalpha():
|
|
8
|
+
return False
|
|
9
|
+
if not re.fullmatch(r"[A-Za-z0-9_-]+", name):
|
|
10
|
+
return False
|
|
11
|
+
if name.startswith(("-", "_")) or name.endswith(("-", "_")):
|
|
12
|
+
return False
|
|
13
|
+
if "__" in name or "--" in name:
|
|
14
|
+
return False
|
|
15
|
+
return True
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _title_part(part: str) -> str:
|
|
19
|
+
if not part:
|
|
20
|
+
return ""
|
|
21
|
+
if part.isdigit():
|
|
22
|
+
return part
|
|
23
|
+
return part[0].upper() + part[1:]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def to_pascal_case(name: str) -> str:
|
|
27
|
+
if "_" in name:
|
|
28
|
+
parts = name.split("_")
|
|
29
|
+
elif "-" in name:
|
|
30
|
+
parts = name.split("-")
|
|
31
|
+
else:
|
|
32
|
+
parts = _CAMEL_PARTS.findall(name) or [name]
|
|
33
|
+
|
|
34
|
+
return "".join(_title_part(part) for part in parts if part)
|