@abuhannaa/create-apptemplate 1.0.12 → 1.1.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/dist/index.js +131 -773
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,679 +4,13 @@
|
|
|
4
4
|
import { intro, outro, isCancel as isCancel2 } from "@clack/prompts";
|
|
5
5
|
import pc3 from "picocolors";
|
|
6
6
|
|
|
7
|
-
// src/types.ts
|
|
8
|
-
var ALL_FEATURES = [
|
|
9
|
-
"auth",
|
|
10
|
-
"userManagement",
|
|
11
|
-
"departments",
|
|
12
|
-
"fileUpload",
|
|
13
|
-
"auditLogs",
|
|
14
|
-
"notifications",
|
|
15
|
-
"dataExport",
|
|
16
|
-
"dashboard"
|
|
17
|
-
];
|
|
18
|
-
|
|
19
|
-
// src/features.ts
|
|
20
|
-
var FEATURE_OPTIONS = [
|
|
21
|
-
{
|
|
22
|
-
value: "auth",
|
|
23
|
-
label: "Authentication (Login, JWT, Guards)",
|
|
24
|
-
hint: "Login/logout pages, JWT middleware, auth guards, profile"
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
value: "userManagement",
|
|
28
|
-
label: "User Management",
|
|
29
|
-
hint: "User CRUD, roles, permissions"
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
value: "departments",
|
|
33
|
-
label: "Departments",
|
|
34
|
-
hint: "Department CRUD module"
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
value: "fileUpload",
|
|
38
|
-
label: "File Management",
|
|
39
|
-
hint: "File upload, download, preview"
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
value: "auditLogs",
|
|
43
|
-
label: "Audit Logging",
|
|
44
|
-
hint: "Track all data changes with audit trail"
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
value: "notifications",
|
|
48
|
-
label: "Notifications",
|
|
49
|
-
hint: "Real-time notification system (WebSocket)"
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
value: "dataExport",
|
|
53
|
-
label: "Data Export",
|
|
54
|
-
hint: "CSV, Excel, PDF export"
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
value: "dashboard",
|
|
58
|
-
label: "Dashboard",
|
|
59
|
-
hint: "Dashboard page with statistics (Requires Users, Depts, Notifications)"
|
|
60
|
-
}
|
|
61
|
-
];
|
|
62
|
-
function applyFeatureDependencies(selected) {
|
|
63
|
-
let result = [...selected];
|
|
64
|
-
if (!result.includes("auth")) {
|
|
65
|
-
result = result.filter((f) => f !== "userManagement" && f !== "departments");
|
|
66
|
-
}
|
|
67
|
-
if (!result.includes("userManagement")) {
|
|
68
|
-
result = result.filter((f) => f !== "departments");
|
|
69
|
-
}
|
|
70
|
-
if (!result.includes("userManagement") || !result.includes("departments") || !result.includes("notifications")) {
|
|
71
|
-
result = result.filter((f) => f !== "dashboard");
|
|
72
|
-
}
|
|
73
|
-
if (!result.includes("userManagement") || !result.includes("departments")) {
|
|
74
|
-
result = result.filter((f) => f !== "dataExport");
|
|
75
|
-
}
|
|
76
|
-
return result;
|
|
77
|
-
}
|
|
78
|
-
var DOTNET_CLEAN_MAP = {
|
|
79
|
-
auth: {
|
|
80
|
-
backend: [
|
|
81
|
-
// Application layer
|
|
82
|
-
"src/Core/App.Template.Application/Features/Authentication",
|
|
83
|
-
"src/Core/App.Template.Application/DTOs/Auth",
|
|
84
|
-
"src/Core/App.Template.Application/Interfaces/IJwtTokenService.cs",
|
|
85
|
-
"src/Core/App.Template.Application/Interfaces/IPasswordHashService.cs",
|
|
86
|
-
"src/Core/App.Template.Application/Interfaces/ISsoAuthService.cs",
|
|
87
|
-
"src/Core/App.Template.Application/Interfaces/IEmailService.cs",
|
|
88
|
-
// Infrastructure layer
|
|
89
|
-
"src/Infrastructure/App.Template.Infrastructure/Services/JwtTokenService.cs",
|
|
90
|
-
"src/Infrastructure/App.Template.Infrastructure/Services/PasswordHashService.cs",
|
|
91
|
-
"src/Infrastructure/App.Template.Infrastructure/Services/SsoAuthService.cs",
|
|
92
|
-
"src/Infrastructure/App.Template.Infrastructure/Services/SsoApiModels.cs",
|
|
93
|
-
"src/Infrastructure/App.Template.Infrastructure/Services/EmailService.cs",
|
|
94
|
-
// Presentation layer
|
|
95
|
-
"src/Presentation/App.Template.WebAPI/Controllers/AuthController.cs",
|
|
96
|
-
"src/Core/App.Template.Application/DTOs/UserDto.cs"
|
|
97
|
-
// Required by Auth
|
|
98
|
-
],
|
|
99
|
-
frontend: []
|
|
100
|
-
// Frontend auth files handled by pattern below
|
|
101
|
-
},
|
|
102
|
-
userManagement: {
|
|
103
|
-
backend: [
|
|
104
|
-
"src/Core/App.Template.Application/Features/UserManagement",
|
|
105
|
-
// 'src/Core/App.Template.Application/DTOs/UserDto.cs', // Moved to auth
|
|
106
|
-
"src/Presentation/App.Template.WebAPI/Controllers/UsersController.cs"
|
|
107
|
-
],
|
|
108
|
-
frontend: []
|
|
109
|
-
},
|
|
110
|
-
departments: {
|
|
111
|
-
backend: [
|
|
112
|
-
"src/Core/App.Template.Application/Features/DepartmentManagement",
|
|
113
|
-
"src/Core/App.Template.Application/DTOs/DepartmentDto.cs",
|
|
114
|
-
"src/Core/App.Template.Application/Interfaces/IOrganizationService.cs",
|
|
115
|
-
"src/Infrastructure/App.Template.Infrastructure/Services/OrganizationService.cs",
|
|
116
|
-
"src/Presentation/App.Template.WebAPI/Controllers/DepartmentsController.cs"
|
|
117
|
-
],
|
|
118
|
-
frontend: []
|
|
119
|
-
},
|
|
120
|
-
fileUpload: {
|
|
121
|
-
backend: [
|
|
122
|
-
"src/Core/App.Template.Application/Features/FileManagement",
|
|
123
|
-
"src/Core/App.Template.Application/DTOs/UploadedFileDto.cs",
|
|
124
|
-
"src/Core/App.Template.Application/Interfaces/IFileStorageService.cs",
|
|
125
|
-
"src/Infrastructure/App.Template.Infrastructure/Services/FileStorageService.cs",
|
|
126
|
-
"src/Presentation/App.Template.WebAPI/Controllers/FilesController.cs"
|
|
127
|
-
],
|
|
128
|
-
frontend: []
|
|
129
|
-
},
|
|
130
|
-
auditLogs: {
|
|
131
|
-
backend: [
|
|
132
|
-
"src/Core/App.Template.Application/Features/AuditLogManagement",
|
|
133
|
-
"src/Core/App.Template.Application/DTOs/AuditLogDto.cs",
|
|
134
|
-
"src/Infrastructure/App.Template.Infrastructure/Persistence/AuditEntry.cs",
|
|
135
|
-
"src/Presentation/App.Template.WebAPI/Controllers/AuditLogsController.cs"
|
|
136
|
-
],
|
|
137
|
-
frontend: []
|
|
138
|
-
},
|
|
139
|
-
notifications: {
|
|
140
|
-
backend: [
|
|
141
|
-
"src/Core/App.Template.Application/Features/NotificationManagement",
|
|
142
|
-
"src/Core/App.Template.Application/DTOs/NotificationDto.cs",
|
|
143
|
-
"src/Core/App.Template.Application/Interfaces/INotificationService.cs",
|
|
144
|
-
"src/Infrastructure/App.Template.Infrastructure/Services/NotificationService.cs",
|
|
145
|
-
"src/Infrastructure/App.Template.Infrastructure/Hubs",
|
|
146
|
-
"src/Infrastructure/App.Template.Infrastructure/SignalR",
|
|
147
|
-
"src/Presentation/App.Template.WebAPI/Controllers/NotificationsController.cs"
|
|
148
|
-
],
|
|
149
|
-
frontend: []
|
|
150
|
-
},
|
|
151
|
-
dataExport: {
|
|
152
|
-
backend: [
|
|
153
|
-
"src/Core/App.Template.Application/Interfaces/IExportService.cs",
|
|
154
|
-
"src/Infrastructure/App.Template.Infrastructure/Services/ExportService.cs",
|
|
155
|
-
"src/Presentation/App.Template.WebAPI/Controllers/ExportController.cs"
|
|
156
|
-
],
|
|
157
|
-
frontend: []
|
|
158
|
-
},
|
|
159
|
-
dashboard: {
|
|
160
|
-
backend: [],
|
|
161
|
-
frontend: []
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
var DOTNET_NLAYER_MAP = {
|
|
165
|
-
auth: {
|
|
166
|
-
backend: [
|
|
167
|
-
"src/App.Template.Api/Controllers/AuthController.cs",
|
|
168
|
-
"src/App.Template.Api/Services/AuthService.cs",
|
|
169
|
-
"src/App.Template.Api/Services/JwtTokenGenerator.cs",
|
|
170
|
-
"src/App.Template.Api/Models/Dtos/AuthDtos.cs",
|
|
171
|
-
"src/App.Template.Api/Models/Dtos/UserDtos.cs"
|
|
172
|
-
// Required by Auth
|
|
173
|
-
],
|
|
174
|
-
frontend: []
|
|
175
|
-
},
|
|
176
|
-
userManagement: {
|
|
177
|
-
backend: [
|
|
178
|
-
"src/App.Template.Api/Controllers/UsersController.cs",
|
|
179
|
-
"src/App.Template.Api/Services/UserService.cs",
|
|
180
|
-
"src/App.Template.Api/Services/IUserService.cs",
|
|
181
|
-
"src/App.Template.Api/Repositories/UserRepository.cs",
|
|
182
|
-
"src/App.Template.Api/Repositories/IUserRepository.cs"
|
|
183
|
-
// 'src/App.Template.Api/Models/Dtos/UserDtos.cs', // Moved to auth
|
|
184
|
-
],
|
|
185
|
-
frontend: []
|
|
186
|
-
},
|
|
187
|
-
departments: {
|
|
188
|
-
backend: [
|
|
189
|
-
"src/App.Template.Api/Controllers/DepartmentsController.cs",
|
|
190
|
-
"src/App.Template.Api/Models/Dtos/DepartmentDtos.cs"
|
|
191
|
-
],
|
|
192
|
-
frontend: []
|
|
193
|
-
},
|
|
194
|
-
fileUpload: {
|
|
195
|
-
backend: [
|
|
196
|
-
"src/App.Template.Api/Controllers/FilesController.cs"
|
|
197
|
-
],
|
|
198
|
-
frontend: []
|
|
199
|
-
},
|
|
200
|
-
auditLogs: {
|
|
201
|
-
backend: [],
|
|
202
|
-
frontend: []
|
|
203
|
-
},
|
|
204
|
-
notifications: {
|
|
205
|
-
backend: [
|
|
206
|
-
"src/App.Template.Api/Controllers/NotificationsController.cs",
|
|
207
|
-
"src/App.Template.Api/Infrastructure/Hubs"
|
|
208
|
-
],
|
|
209
|
-
frontend: []
|
|
210
|
-
},
|
|
211
|
-
dataExport: {
|
|
212
|
-
backend: [
|
|
213
|
-
"src/App.Template.Api/Controllers/ExportController.cs"
|
|
214
|
-
],
|
|
215
|
-
frontend: []
|
|
216
|
-
},
|
|
217
|
-
dashboard: {
|
|
218
|
-
backend: [],
|
|
219
|
-
frontend: []
|
|
220
|
-
}
|
|
221
|
-
};
|
|
222
|
-
var DOTNET_FEATURE_MAP = {
|
|
223
|
-
auth: {
|
|
224
|
-
backend: [
|
|
225
|
-
"src/App.Template.Api/Features/Auth"
|
|
226
|
-
],
|
|
227
|
-
frontend: []
|
|
228
|
-
},
|
|
229
|
-
userManagement: {
|
|
230
|
-
backend: [
|
|
231
|
-
// 'src/App.Template.Api/Features/Users', // Don't remove whole folder, Auth needs Entity/Repo/DTOs
|
|
232
|
-
"src/App.Template.Api/Features/Users/UsersController.cs",
|
|
233
|
-
"src/App.Template.Api/Features/Users/UserService.cs",
|
|
234
|
-
"src/App.Template.Api/Features/Users/IUserService.cs"
|
|
235
|
-
],
|
|
236
|
-
frontend: []
|
|
237
|
-
},
|
|
238
|
-
departments: {
|
|
239
|
-
backend: [
|
|
240
|
-
"src/App.Template.Api/Features/Departments"
|
|
241
|
-
],
|
|
242
|
-
frontend: []
|
|
243
|
-
},
|
|
244
|
-
fileUpload: {
|
|
245
|
-
backend: [
|
|
246
|
-
"src/App.Template.Api/Features/Files"
|
|
247
|
-
],
|
|
248
|
-
frontend: []
|
|
249
|
-
},
|
|
250
|
-
auditLogs: {
|
|
251
|
-
backend: [],
|
|
252
|
-
frontend: []
|
|
253
|
-
},
|
|
254
|
-
notifications: {
|
|
255
|
-
backend: [
|
|
256
|
-
"src/App.Template.Api/Features/Notifications"
|
|
257
|
-
],
|
|
258
|
-
frontend: []
|
|
259
|
-
},
|
|
260
|
-
dataExport: {
|
|
261
|
-
backend: [
|
|
262
|
-
"src/App.Template.Api/Features/Export"
|
|
263
|
-
],
|
|
264
|
-
frontend: []
|
|
265
|
-
},
|
|
266
|
-
dashboard: {
|
|
267
|
-
backend: [],
|
|
268
|
-
frontend: []
|
|
269
|
-
}
|
|
270
|
-
};
|
|
271
|
-
var SPRING_CLEAN_MAP = {
|
|
272
|
-
auth: {
|
|
273
|
-
backend: [
|
|
274
|
-
"api/src/main/java/apptemplate/api/controllers/AuthController.java"
|
|
275
|
-
],
|
|
276
|
-
frontend: []
|
|
277
|
-
},
|
|
278
|
-
userManagement: {
|
|
279
|
-
backend: [
|
|
280
|
-
"api/src/main/java/apptemplate/api/controllers/UsersController.java"
|
|
281
|
-
],
|
|
282
|
-
frontend: []
|
|
283
|
-
},
|
|
284
|
-
departments: {
|
|
285
|
-
backend: [
|
|
286
|
-
"api/src/main/java/apptemplate/api/controllers/DepartmentsController.java"
|
|
287
|
-
],
|
|
288
|
-
frontend: []
|
|
289
|
-
},
|
|
290
|
-
fileUpload: {
|
|
291
|
-
backend: [
|
|
292
|
-
"api/src/main/java/apptemplate/api/controllers/FilesController.java"
|
|
293
|
-
],
|
|
294
|
-
frontend: []
|
|
295
|
-
},
|
|
296
|
-
auditLogs: {
|
|
297
|
-
backend: [
|
|
298
|
-
"api/src/main/java/apptemplate/api/controllers/AuditLogsController.java"
|
|
299
|
-
],
|
|
300
|
-
frontend: []
|
|
301
|
-
},
|
|
302
|
-
notifications: {
|
|
303
|
-
backend: [
|
|
304
|
-
"api/src/main/java/apptemplate/api/controllers/NotificationsController.java"
|
|
305
|
-
],
|
|
306
|
-
frontend: []
|
|
307
|
-
},
|
|
308
|
-
dataExport: {
|
|
309
|
-
backend: [
|
|
310
|
-
"api/src/main/java/apptemplate/api/controllers/ExportController.java"
|
|
311
|
-
],
|
|
312
|
-
frontend: []
|
|
313
|
-
},
|
|
314
|
-
dashboard: {
|
|
315
|
-
backend: [],
|
|
316
|
-
frontend: []
|
|
317
|
-
}
|
|
318
|
-
};
|
|
319
|
-
var SPRING_NLAYER_MAP = {
|
|
320
|
-
auth: {
|
|
321
|
-
backend: [
|
|
322
|
-
"src/main/java/com/apptemplate/api/controller/AuthController.java"
|
|
323
|
-
],
|
|
324
|
-
frontend: []
|
|
325
|
-
},
|
|
326
|
-
userManagement: {
|
|
327
|
-
backend: [
|
|
328
|
-
"src/main/java/com/apptemplate/api/controller/UserController.java"
|
|
329
|
-
],
|
|
330
|
-
frontend: []
|
|
331
|
-
},
|
|
332
|
-
departments: {
|
|
333
|
-
backend: [
|
|
334
|
-
"src/main/java/com/apptemplate/api/controller/DepartmentController.java"
|
|
335
|
-
],
|
|
336
|
-
frontend: []
|
|
337
|
-
},
|
|
338
|
-
fileUpload: {
|
|
339
|
-
backend: [
|
|
340
|
-
"src/main/java/com/apptemplate/api/controller/FileController.java"
|
|
341
|
-
],
|
|
342
|
-
frontend: []
|
|
343
|
-
},
|
|
344
|
-
auditLogs: {
|
|
345
|
-
backend: [
|
|
346
|
-
"src/main/java/com/apptemplate/api/audit"
|
|
347
|
-
],
|
|
348
|
-
frontend: []
|
|
349
|
-
},
|
|
350
|
-
notifications: {
|
|
351
|
-
backend: [
|
|
352
|
-
"src/main/java/com/apptemplate/api/controller/NotificationController.java"
|
|
353
|
-
],
|
|
354
|
-
frontend: []
|
|
355
|
-
},
|
|
356
|
-
dataExport: {
|
|
357
|
-
backend: [
|
|
358
|
-
"src/main/java/com/apptemplate/api/controller/ExportController.java"
|
|
359
|
-
],
|
|
360
|
-
frontend: []
|
|
361
|
-
},
|
|
362
|
-
dashboard: {
|
|
363
|
-
backend: [],
|
|
364
|
-
frontend: []
|
|
365
|
-
}
|
|
366
|
-
};
|
|
367
|
-
var SPRING_FEATURE_MAP = {
|
|
368
|
-
auth: {
|
|
369
|
-
backend: [
|
|
370
|
-
"src/main/java/com/apptemplate/api/features/auth"
|
|
371
|
-
],
|
|
372
|
-
frontend: []
|
|
373
|
-
},
|
|
374
|
-
userManagement: {
|
|
375
|
-
backend: [
|
|
376
|
-
"src/main/java/com/apptemplate/api/features/users"
|
|
377
|
-
],
|
|
378
|
-
frontend: []
|
|
379
|
-
},
|
|
380
|
-
departments: {
|
|
381
|
-
backend: [
|
|
382
|
-
"src/main/java/com/apptemplate/api/features/departments"
|
|
383
|
-
],
|
|
384
|
-
frontend: []
|
|
385
|
-
},
|
|
386
|
-
fileUpload: {
|
|
387
|
-
backend: [
|
|
388
|
-
"src/main/java/com/apptemplate/api/features/files"
|
|
389
|
-
],
|
|
390
|
-
frontend: []
|
|
391
|
-
},
|
|
392
|
-
auditLogs: {
|
|
393
|
-
backend: [
|
|
394
|
-
"src/main/java/com/apptemplate/api/common/audit"
|
|
395
|
-
],
|
|
396
|
-
frontend: []
|
|
397
|
-
},
|
|
398
|
-
notifications: {
|
|
399
|
-
backend: [
|
|
400
|
-
"src/main/java/com/apptemplate/api/features/notifications"
|
|
401
|
-
],
|
|
402
|
-
frontend: []
|
|
403
|
-
},
|
|
404
|
-
dataExport: {
|
|
405
|
-
backend: [
|
|
406
|
-
"src/main/java/com/apptemplate/api/features/export"
|
|
407
|
-
],
|
|
408
|
-
frontend: []
|
|
409
|
-
},
|
|
410
|
-
dashboard: {
|
|
411
|
-
backend: [],
|
|
412
|
-
frontend: []
|
|
413
|
-
}
|
|
414
|
-
};
|
|
415
|
-
var NESTJS_CLEAN_MAP = {
|
|
416
|
-
auth: {
|
|
417
|
-
backend: [
|
|
418
|
-
"src/modules/auth"
|
|
419
|
-
],
|
|
420
|
-
frontend: []
|
|
421
|
-
},
|
|
422
|
-
userManagement: {
|
|
423
|
-
backend: [
|
|
424
|
-
"src/modules/user-management"
|
|
425
|
-
],
|
|
426
|
-
frontend: []
|
|
427
|
-
},
|
|
428
|
-
departments: {
|
|
429
|
-
backend: [
|
|
430
|
-
"src/modules/department-management"
|
|
431
|
-
],
|
|
432
|
-
frontend: []
|
|
433
|
-
},
|
|
434
|
-
fileUpload: {
|
|
435
|
-
backend: [
|
|
436
|
-
"src/modules/file-management"
|
|
437
|
-
],
|
|
438
|
-
frontend: []
|
|
439
|
-
},
|
|
440
|
-
auditLogs: {
|
|
441
|
-
backend: [
|
|
442
|
-
"src/modules/audit-log"
|
|
443
|
-
],
|
|
444
|
-
frontend: []
|
|
445
|
-
},
|
|
446
|
-
notifications: {
|
|
447
|
-
backend: [
|
|
448
|
-
"src/modules/notification"
|
|
449
|
-
],
|
|
450
|
-
frontend: []
|
|
451
|
-
},
|
|
452
|
-
dataExport: {
|
|
453
|
-
backend: [
|
|
454
|
-
"src/modules/export"
|
|
455
|
-
],
|
|
456
|
-
frontend: []
|
|
457
|
-
},
|
|
458
|
-
dashboard: {
|
|
459
|
-
backend: [],
|
|
460
|
-
frontend: []
|
|
461
|
-
}
|
|
462
|
-
};
|
|
463
|
-
var NESTJS_NLAYER_MAP = {
|
|
464
|
-
auth: {
|
|
465
|
-
backend: [
|
|
466
|
-
"src/auth"
|
|
467
|
-
],
|
|
468
|
-
frontend: []
|
|
469
|
-
},
|
|
470
|
-
userManagement: {
|
|
471
|
-
backend: [],
|
|
472
|
-
frontend: []
|
|
473
|
-
},
|
|
474
|
-
departments: {
|
|
475
|
-
backend: [
|
|
476
|
-
"src/modules/departments"
|
|
477
|
-
],
|
|
478
|
-
frontend: []
|
|
479
|
-
},
|
|
480
|
-
fileUpload: {
|
|
481
|
-
backend: [
|
|
482
|
-
"src/modules/files"
|
|
483
|
-
],
|
|
484
|
-
frontend: []
|
|
485
|
-
},
|
|
486
|
-
auditLogs: {
|
|
487
|
-
backend: [],
|
|
488
|
-
frontend: []
|
|
489
|
-
},
|
|
490
|
-
notifications: {
|
|
491
|
-
backend: [
|
|
492
|
-
"src/modules/notifications"
|
|
493
|
-
],
|
|
494
|
-
frontend: []
|
|
495
|
-
},
|
|
496
|
-
dataExport: {
|
|
497
|
-
backend: [
|
|
498
|
-
"src/modules/export"
|
|
499
|
-
],
|
|
500
|
-
frontend: []
|
|
501
|
-
},
|
|
502
|
-
dashboard: {
|
|
503
|
-
backend: [],
|
|
504
|
-
frontend: []
|
|
505
|
-
}
|
|
506
|
-
};
|
|
507
|
-
var NESTJS_FEATURE_MAP = {
|
|
508
|
-
auth: {
|
|
509
|
-
backend: [
|
|
510
|
-
"src/features/auth"
|
|
511
|
-
],
|
|
512
|
-
frontend: []
|
|
513
|
-
},
|
|
514
|
-
userManagement: {
|
|
515
|
-
backend: [
|
|
516
|
-
"src/features/users"
|
|
517
|
-
],
|
|
518
|
-
frontend: []
|
|
519
|
-
},
|
|
520
|
-
departments: {
|
|
521
|
-
backend: [
|
|
522
|
-
"src/features/departments"
|
|
523
|
-
],
|
|
524
|
-
frontend: []
|
|
525
|
-
},
|
|
526
|
-
fileUpload: {
|
|
527
|
-
backend: [
|
|
528
|
-
"src/features/files"
|
|
529
|
-
],
|
|
530
|
-
frontend: []
|
|
531
|
-
},
|
|
532
|
-
auditLogs: {
|
|
533
|
-
backend: [],
|
|
534
|
-
frontend: []
|
|
535
|
-
},
|
|
536
|
-
notifications: {
|
|
537
|
-
backend: [
|
|
538
|
-
"src/features/notifications"
|
|
539
|
-
],
|
|
540
|
-
frontend: []
|
|
541
|
-
},
|
|
542
|
-
dataExport: {
|
|
543
|
-
backend: [
|
|
544
|
-
"src/features/export"
|
|
545
|
-
],
|
|
546
|
-
frontend: []
|
|
547
|
-
},
|
|
548
|
-
dashboard: {
|
|
549
|
-
backend: [],
|
|
550
|
-
frontend: []
|
|
551
|
-
}
|
|
552
|
-
};
|
|
553
|
-
var VUE_FRONTEND_MAP = {
|
|
554
|
-
auth: [
|
|
555
|
-
"src/pages/login.vue",
|
|
556
|
-
"src/pages/forgot-password.vue",
|
|
557
|
-
"src/pages/reset-password.vue",
|
|
558
|
-
"src/pages/profile.vue",
|
|
559
|
-
"src/stores/auth.js",
|
|
560
|
-
"src/services/authApi.js"
|
|
561
|
-
],
|
|
562
|
-
userManagement: [
|
|
563
|
-
"src/pages/users",
|
|
564
|
-
"src/stores/user.js",
|
|
565
|
-
"src/services/userApi.js"
|
|
566
|
-
],
|
|
567
|
-
departments: [
|
|
568
|
-
"src/pages/departments",
|
|
569
|
-
"src/stores/department.js",
|
|
570
|
-
"src/services/departmentApi.js"
|
|
571
|
-
],
|
|
572
|
-
fileUpload: [
|
|
573
|
-
"src/pages/files",
|
|
574
|
-
"src/services/fileService.js"
|
|
575
|
-
],
|
|
576
|
-
auditLogs: [
|
|
577
|
-
"src/pages/audit-logs",
|
|
578
|
-
"src/services/auditLogService.js"
|
|
579
|
-
],
|
|
580
|
-
notifications: [
|
|
581
|
-
"src/pages/notifications",
|
|
582
|
-
"src/stores/notification.js",
|
|
583
|
-
"src/stores/persistentNotification.js",
|
|
584
|
-
"src/services/notificationApi.js"
|
|
585
|
-
],
|
|
586
|
-
dataExport: [
|
|
587
|
-
"src/services/exportService.js"
|
|
588
|
-
],
|
|
589
|
-
dashboard: [
|
|
590
|
-
"src/pages/dashboard.vue"
|
|
591
|
-
]
|
|
592
|
-
};
|
|
593
|
-
var REACT_FRONTEND_MAP = {
|
|
594
|
-
auth: [
|
|
595
|
-
"src/pages/Login.tsx",
|
|
596
|
-
"src/pages/ForgotPassword.tsx",
|
|
597
|
-
"src/pages/ResetPassword.tsx",
|
|
598
|
-
"src/pages/Profile.tsx",
|
|
599
|
-
"src/stores/authStore.ts",
|
|
600
|
-
"src/services/authApi.ts"
|
|
601
|
-
],
|
|
602
|
-
userManagement: [
|
|
603
|
-
"src/pages/Users.tsx",
|
|
604
|
-
"src/stores/userStore.ts",
|
|
605
|
-
"src/services/userApi.ts"
|
|
606
|
-
],
|
|
607
|
-
departments: [
|
|
608
|
-
"src/pages/Departments.tsx",
|
|
609
|
-
"src/stores/departmentStore.ts",
|
|
610
|
-
"src/services/departmentApi.ts"
|
|
611
|
-
],
|
|
612
|
-
fileUpload: [
|
|
613
|
-
"src/pages/FilesPage.tsx",
|
|
614
|
-
"src/services/fileService.ts"
|
|
615
|
-
],
|
|
616
|
-
auditLogs: [
|
|
617
|
-
"src/pages/AuditLogsPage.tsx",
|
|
618
|
-
"src/pages/AuditLogs.tsx",
|
|
619
|
-
"src/services/auditLogService.ts"
|
|
620
|
-
],
|
|
621
|
-
notifications: [
|
|
622
|
-
"src/pages/Notifications.tsx",
|
|
623
|
-
"src/stores/notificationStore.ts",
|
|
624
|
-
"src/stores/persistentNotificationStore.ts",
|
|
625
|
-
"src/services/notificationApi.ts"
|
|
626
|
-
],
|
|
627
|
-
dataExport: [
|
|
628
|
-
"src/services/exportService.ts"
|
|
629
|
-
],
|
|
630
|
-
dashboard: [
|
|
631
|
-
"src/pages/Dashboard.tsx",
|
|
632
|
-
"src/pages/Dashboard.scss"
|
|
633
|
-
]
|
|
634
|
-
};
|
|
635
|
-
function getBackendFileMap(backend, architecture) {
|
|
636
|
-
const key = `${backend}-${architecture}`;
|
|
637
|
-
switch (key) {
|
|
638
|
-
case "dotnet-clean":
|
|
639
|
-
return DOTNET_CLEAN_MAP;
|
|
640
|
-
case "dotnet-nlayer":
|
|
641
|
-
return DOTNET_NLAYER_MAP;
|
|
642
|
-
case "dotnet-feature":
|
|
643
|
-
return DOTNET_FEATURE_MAP;
|
|
644
|
-
case "spring-clean":
|
|
645
|
-
return SPRING_CLEAN_MAP;
|
|
646
|
-
case "spring-nlayer":
|
|
647
|
-
return SPRING_NLAYER_MAP;
|
|
648
|
-
case "spring-feature":
|
|
649
|
-
return SPRING_FEATURE_MAP;
|
|
650
|
-
case "nestjs-clean":
|
|
651
|
-
return NESTJS_CLEAN_MAP;
|
|
652
|
-
case "nestjs-nlayer":
|
|
653
|
-
return NESTJS_NLAYER_MAP;
|
|
654
|
-
case "nestjs-feature":
|
|
655
|
-
return NESTJS_FEATURE_MAP;
|
|
656
|
-
default:
|
|
657
|
-
return {};
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
function getFrontendFileMap(frontendFramework) {
|
|
661
|
-
return frontendFramework === "vue" ? VUE_FRONTEND_MAP : REACT_FRONTEND_MAP;
|
|
662
|
-
}
|
|
663
|
-
function getFeaturesLabel(features, allFeatures) {
|
|
664
|
-
if (features.length === allFeatures.length) {
|
|
665
|
-
return "All features";
|
|
666
|
-
}
|
|
667
|
-
if (features.length === 0) {
|
|
668
|
-
return "None (bare template)";
|
|
669
|
-
}
|
|
670
|
-
return features.map((f) => FEATURE_OPTIONS.find((o) => o.value === f)?.label || f).join(", ");
|
|
671
|
-
}
|
|
672
|
-
|
|
673
7
|
// src/cli.ts
|
|
674
8
|
var validProjectTypes = ["fullstack", "backend", "frontend"];
|
|
675
9
|
var validBackends = ["dotnet", "spring", "nestjs"];
|
|
676
10
|
var validArchitectures = ["clean", "nlayer", "feature"];
|
|
677
11
|
var validFrontendFrameworks = ["vue", "react"];
|
|
678
12
|
var validUILibraries = ["vuetify", "primevue", "primereact", "mui"];
|
|
679
|
-
var
|
|
13
|
+
var validVariants = ["minimal", "full"];
|
|
680
14
|
function parseArgs() {
|
|
681
15
|
const args = process.argv.slice(2);
|
|
682
16
|
const result = {};
|
|
@@ -763,20 +97,12 @@ function parseArgs() {
|
|
|
763
97
|
i++;
|
|
764
98
|
continue;
|
|
765
99
|
}
|
|
766
|
-
if (arg === "
|
|
100
|
+
if (arg === "-V" || arg === "--variant") {
|
|
767
101
|
const value = args[++i];
|
|
768
|
-
if (value) {
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
}
|
|
772
|
-
const requested = value.split(",").map((s) => s.trim());
|
|
773
|
-
const valid = requested.filter((f) => validFeatures.includes(f));
|
|
774
|
-
const invalid = requested.filter((f) => !validFeatures.includes(f));
|
|
775
|
-
if (invalid.length > 0) {
|
|
776
|
-
console.warn(`Warning: Invalid features "${invalid.join(", ")}". Valid options: ${validFeatures.join(", ")}`);
|
|
777
|
-
}
|
|
778
|
-
result.features = applyFeatureDependencies(valid);
|
|
779
|
-
}
|
|
102
|
+
if (isValidVariant(value)) {
|
|
103
|
+
result.variant = value;
|
|
104
|
+
} else {
|
|
105
|
+
console.warn(`Warning: Invalid variant "${value}". Valid options: ${validVariants.join(", ")}`);
|
|
780
106
|
}
|
|
781
107
|
i++;
|
|
782
108
|
continue;
|
|
@@ -803,6 +129,9 @@ function isValidFrontendFramework(value) {
|
|
|
803
129
|
function isValidUI(value) {
|
|
804
130
|
return value !== void 0 && validUILibraries.includes(value);
|
|
805
131
|
}
|
|
132
|
+
function isValidVariant(value) {
|
|
133
|
+
return value !== void 0 && validVariants.includes(value);
|
|
134
|
+
}
|
|
806
135
|
function isValidProjectName(value) {
|
|
807
136
|
if (!value) return false;
|
|
808
137
|
const pattern = /^[A-Za-z][A-Za-z0-9]*(\.[A-Za-z][A-Za-z0-9]*)+$/;
|
|
@@ -961,25 +290,25 @@ async function runInteractivePrompts(cliArgs) {
|
|
|
961
290
|
if (p.isCancel(result)) return result;
|
|
962
291
|
ui = result;
|
|
963
292
|
}
|
|
964
|
-
let
|
|
965
|
-
if (!cliArgs.
|
|
966
|
-
const result = await p.
|
|
967
|
-
message: "Which
|
|
968
|
-
options:
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
293
|
+
let variant = cliArgs.variant || "full";
|
|
294
|
+
if (!cliArgs.variant) {
|
|
295
|
+
const result = await p.select({
|
|
296
|
+
message: "Which template variant would you like?",
|
|
297
|
+
options: [
|
|
298
|
+
{
|
|
299
|
+
value: "full",
|
|
300
|
+
label: "Full",
|
|
301
|
+
hint: "User management, departments, dashboard, all features"
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
value: "minimal",
|
|
305
|
+
label: "Minimal",
|
|
306
|
+
hint: "Auth, files, audit logs, notifications (no user/dept management)"
|
|
307
|
+
}
|
|
308
|
+
]
|
|
975
309
|
});
|
|
976
310
|
if (p.isCancel(result)) return result;
|
|
977
|
-
|
|
978
|
-
if (features.length < result.length) {
|
|
979
|
-
const removed = result.filter((f) => !features.includes(f));
|
|
980
|
-
const removedLabels = removed.map((f) => FEATURE_OPTIONS.find((o) => o.value === f)?.label || f);
|
|
981
|
-
console.log(pc.yellow(` \u26A0 Auto-removed due to dependencies: ${removedLabels.join(", ")}`));
|
|
982
|
-
}
|
|
311
|
+
variant = result;
|
|
983
312
|
}
|
|
984
313
|
let projectName = cliArgs.projectName;
|
|
985
314
|
const needsNamespace = projectType !== "frontend" && (backend === "dotnet" || backend === "spring");
|
|
@@ -1033,7 +362,7 @@ async function runInteractivePrompts(cliArgs) {
|
|
|
1033
362
|
summaryLines.push(`${pc.cyan("Frontend:")} ${getFrontendLabel(frontendFramework)}`);
|
|
1034
363
|
summaryLines.push(`${pc.cyan("UI Library:")} ${getUILabel(ui)}`);
|
|
1035
364
|
}
|
|
1036
|
-
summaryLines.push(`${pc.cyan("
|
|
365
|
+
summaryLines.push(`${pc.cyan("Template:")} ${getVariantLabel(variant)}`);
|
|
1037
366
|
if (needsNamespace && projectName) {
|
|
1038
367
|
summaryLines.push(`${pc.cyan("Namespace:")} ${projectName}`);
|
|
1039
368
|
}
|
|
@@ -1059,7 +388,7 @@ async function runInteractivePrompts(cliArgs) {
|
|
|
1059
388
|
projectName,
|
|
1060
389
|
installDeps,
|
|
1061
390
|
placeInRoot,
|
|
1062
|
-
|
|
391
|
+
variant
|
|
1063
392
|
};
|
|
1064
393
|
}
|
|
1065
394
|
function toPascalCase(str) {
|
|
@@ -1097,6 +426,13 @@ function getUILabel(ui) {
|
|
|
1097
426
|
};
|
|
1098
427
|
return labels[ui];
|
|
1099
428
|
}
|
|
429
|
+
function getVariantLabel(variant) {
|
|
430
|
+
const labels = {
|
|
431
|
+
full: "Full (all features)",
|
|
432
|
+
minimal: "Minimal (no user/dept management)"
|
|
433
|
+
};
|
|
434
|
+
return labels[variant];
|
|
435
|
+
}
|
|
1100
436
|
|
|
1101
437
|
// src/generator.ts
|
|
1102
438
|
import * as p2 from "@clack/prompts";
|
|
@@ -1108,7 +444,18 @@ import fs5 from "fs";
|
|
|
1108
444
|
import degit from "degit";
|
|
1109
445
|
import path2 from "path";
|
|
1110
446
|
import fs2 from "fs";
|
|
1111
|
-
async function
|
|
447
|
+
async function downloadBackendTemplate(repo, backend, architecture, variant, destPath) {
|
|
448
|
+
const folder = `backend/${backend}/${architecture}-architecture/${variant}`;
|
|
449
|
+
const source = `${repo}/${folder}`;
|
|
450
|
+
const emitter = degit(source, {
|
|
451
|
+
cache: false,
|
|
452
|
+
force: true,
|
|
453
|
+
verbose: false
|
|
454
|
+
});
|
|
455
|
+
await emitter.clone(destPath);
|
|
456
|
+
}
|
|
457
|
+
async function downloadFrontendTemplate(repo, framework, ui, variant, destPath) {
|
|
458
|
+
const folder = `frontend/${framework}/${ui}/${variant}`;
|
|
1112
459
|
const source = `${repo}/${folder}`;
|
|
1113
460
|
const emitter = degit(source, {
|
|
1114
461
|
cache: false,
|
|
@@ -1207,12 +554,16 @@ async function renameDotNetProject(projectPath, config, newDotName, newNamespace
|
|
|
1207
554
|
}
|
|
1208
555
|
if (!fs3.existsSync(backendDir)) return;
|
|
1209
556
|
const folderMappings = [
|
|
557
|
+
// Clean architecture (multi-project layout)
|
|
1210
558
|
["src/Core/App.Template.Domain", `src/Core/${newDotName}.Domain`],
|
|
1211
559
|
["src/Core/App.Template.Application", `src/Core/${newDotName}.Application`],
|
|
1212
560
|
["src/Infrastructure/App.Template.Infrastructure", `src/Infrastructure/${newDotName}.Infrastructure`],
|
|
1213
561
|
["src/Presentation/App.Template.WebAPI", `src/Presentation/${newDotName}.WebAPI`],
|
|
1214
562
|
["tests/App.Template.Domain.Tests", `tests/${newDotName}.Domain.Tests`],
|
|
1215
|
-
["tests/App.Template.Application.Tests", `tests/${newDotName}.Application.Tests`]
|
|
563
|
+
["tests/App.Template.Application.Tests", `tests/${newDotName}.Application.Tests`],
|
|
564
|
+
// Feature and NLayer architectures (single-project layout)
|
|
565
|
+
["src/App.Template.Api", `src/${newDotName}.Api`],
|
|
566
|
+
["tests/App.Template.Api.Tests", `tests/${newDotName}.Api.Tests`]
|
|
1216
567
|
];
|
|
1217
568
|
for (const [oldFolder, newFolder] of folderMappings) {
|
|
1218
569
|
const oldPath = path3.join(backendDir, oldFolder);
|
|
@@ -1234,6 +585,39 @@ async function renameDotNetProject(projectPath, config, newDotName, newNamespace
|
|
|
1234
585
|
return content.replace(/App\.Template/g, newDotName).replace(/AppTemplate/g, newNamespace);
|
|
1235
586
|
});
|
|
1236
587
|
}
|
|
588
|
+
function renameJavaPackageDir(oldDir, newDir) {
|
|
589
|
+
if (!fs3.existsSync(oldDir)) return;
|
|
590
|
+
const resolvedOld = path3.resolve(oldDir);
|
|
591
|
+
const resolvedNew = path3.resolve(newDir);
|
|
592
|
+
if (resolvedOld === resolvedNew) return;
|
|
593
|
+
if (fs3.existsSync(resolvedNew)) {
|
|
594
|
+
for (const entry of fs3.readdirSync(resolvedOld, { withFileTypes: true })) {
|
|
595
|
+
fs3.renameSync(
|
|
596
|
+
path3.join(resolvedOld, entry.name),
|
|
597
|
+
path3.join(resolvedNew, entry.name)
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
fs3.rmdirSync(resolvedOld);
|
|
601
|
+
} else {
|
|
602
|
+
fs3.mkdirSync(path3.dirname(resolvedNew), { recursive: true });
|
|
603
|
+
fs3.renameSync(resolvedOld, resolvedNew);
|
|
604
|
+
}
|
|
605
|
+
let current = path3.dirname(resolvedOld);
|
|
606
|
+
while (path3.basename(current) !== "java") {
|
|
607
|
+
if (!fs3.existsSync(current)) break;
|
|
608
|
+
try {
|
|
609
|
+
const remaining = fs3.readdirSync(current);
|
|
610
|
+
if (remaining.length === 0) {
|
|
611
|
+
fs3.rmdirSync(current);
|
|
612
|
+
current = path3.dirname(current);
|
|
613
|
+
} else {
|
|
614
|
+
break;
|
|
615
|
+
}
|
|
616
|
+
} catch {
|
|
617
|
+
break;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
1237
621
|
async function renameSpringProject(projectPath, config, newDotName) {
|
|
1238
622
|
let backendDir;
|
|
1239
623
|
if (config.projectType === "fullstack") {
|
|
@@ -1246,15 +630,43 @@ async function renameSpringProject(projectPath, config, newDotName) {
|
|
|
1246
630
|
if (!fs3.existsSync(backendDir)) return;
|
|
1247
631
|
const packageName = newDotName.toLowerCase().replace(/\./g, ".");
|
|
1248
632
|
const artifactId = newDotName.toLowerCase().replace(/\./g, "-");
|
|
1249
|
-
const
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
633
|
+
const pkgPath = newDotName.toLowerCase().replace(/\./g, "/");
|
|
634
|
+
const compactName = newDotName.replace(/\./g, "").toLowerCase();
|
|
635
|
+
const displayName = newDotName.replace(/\./g, "");
|
|
636
|
+
const isClean = config.architecture === "clean";
|
|
637
|
+
await updateFileContents(backendDir, [".xml"], (content) => {
|
|
638
|
+
return content.replace(/<artifactId>app-template<\/artifactId>/g, `<artifactId>${artifactId}</artifactId>`).replace(/com\.apptemplate/g, packageName).replace(/AppTemplate/g, displayName);
|
|
639
|
+
});
|
|
640
|
+
await updateFileContents(backendDir, [".yml", ".yaml", ".properties"], (content) => {
|
|
641
|
+
if (isClean) {
|
|
642
|
+
return content.replace(/AppTemplate/g, displayName).replace(/apptemplate\.local/g, `${compactName}.local`).replace(/apptemplate_(\w+)/g, `${compactName}_$1`).replace(/\bapptemplate\b/g, packageName);
|
|
643
|
+
} else {
|
|
644
|
+
return content.replace(/AppTemplate/g, displayName).replace(/com\.apptemplate/g, packageName);
|
|
645
|
+
}
|
|
646
|
+
});
|
|
1255
647
|
await updateFileContents(backendDir, [".java"], (content) => {
|
|
1256
|
-
|
|
648
|
+
if (isClean) {
|
|
649
|
+
return content.replace(/apptemplate\.local/g, `${compactName}.local`).replace(/\bapptemplate\b/g, packageName);
|
|
650
|
+
} else {
|
|
651
|
+
return content.replace(/com\.apptemplate/g, packageName);
|
|
652
|
+
}
|
|
1257
653
|
});
|
|
654
|
+
if (isClean) {
|
|
655
|
+
const modules = ["api", "application", "domain", "infrastructure"];
|
|
656
|
+
for (const module of modules) {
|
|
657
|
+
for (const sourceRoot of ["src/main/java", "src/test/java"]) {
|
|
658
|
+
const oldDir = path3.join(backendDir, module, sourceRoot, "apptemplate");
|
|
659
|
+
const newDir = path3.join(backendDir, module, sourceRoot, pkgPath);
|
|
660
|
+
renameJavaPackageDir(oldDir, newDir);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
} else {
|
|
664
|
+
for (const sourceRoot of ["src/main/java", "src/test/java"]) {
|
|
665
|
+
const oldDir = path3.join(backendDir, sourceRoot, "com", "apptemplate");
|
|
666
|
+
const newDir = path3.join(backendDir, sourceRoot, ...packageName.split("."));
|
|
667
|
+
renameJavaPackageDir(oldDir, newDir);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
1258
670
|
}
|
|
1259
671
|
async function updateCommonFiles(projectPath, _config, newDotName, newNamespace) {
|
|
1260
672
|
const filesToUpdate = [
|
|
@@ -1309,7 +721,7 @@ function getAllFiles(dir) {
|
|
|
1309
721
|
for (const entry of entries) {
|
|
1310
722
|
const fullPath = path3.join(dir, entry.name);
|
|
1311
723
|
if (entry.isDirectory()) {
|
|
1312
|
-
if (!["node_modules", ".git", "bin", "obj", "dist", "build"].includes(entry.name)) {
|
|
724
|
+
if (!["node_modules", ".git", "bin", "obj", "dist", "build", "target"].includes(entry.name)) {
|
|
1313
725
|
files.push(...getAllFiles(fullPath));
|
|
1314
726
|
}
|
|
1315
727
|
} else {
|
|
@@ -1436,8 +848,6 @@ async function generateProject(config) {
|
|
|
1436
848
|
spinner2.start("Downloading templates...");
|
|
1437
849
|
try {
|
|
1438
850
|
if (config.projectType !== "frontend") {
|
|
1439
|
-
const archSuffix = config.architecture === "clean" ? "" : `-${config.architecture}`;
|
|
1440
|
-
const sourceFolder = `backend-${config.backend}${archSuffix}`;
|
|
1441
851
|
let destFolder;
|
|
1442
852
|
if (config.projectType === "fullstack") {
|
|
1443
853
|
destFolder = "backend";
|
|
@@ -1445,11 +855,10 @@ async function generateProject(config) {
|
|
|
1445
855
|
destFolder = config.placeInRoot ? "" : "backend";
|
|
1446
856
|
}
|
|
1447
857
|
const destPath = destFolder ? path5.join(absolutePath, destFolder) : absolutePath;
|
|
1448
|
-
await
|
|
1449
|
-
spinner2.message(`Downloaded
|
|
858
|
+
await downloadBackendTemplate(REPO, config.backend, config.architecture, config.variant, destPath);
|
|
859
|
+
spinner2.message(`Downloaded backend-${config.backend}-${config.architecture}-${config.variant}`);
|
|
1450
860
|
}
|
|
1451
861
|
if (config.projectType !== "backend") {
|
|
1452
|
-
const sourceFolder = `frontend-${config.ui}`;
|
|
1453
862
|
let destFolder;
|
|
1454
863
|
if (config.projectType === "fullstack") {
|
|
1455
864
|
destFolder = "frontend";
|
|
@@ -1457,8 +866,8 @@ async function generateProject(config) {
|
|
|
1457
866
|
destFolder = config.placeInRoot ? "" : "frontend";
|
|
1458
867
|
}
|
|
1459
868
|
const destPath = destFolder ? path5.join(absolutePath, destFolder) : absolutePath;
|
|
1460
|
-
await
|
|
1461
|
-
spinner2.message(`Downloaded
|
|
869
|
+
await downloadFrontendTemplate(REPO, config.frontendFramework, config.ui, config.variant, destPath);
|
|
870
|
+
spinner2.message(`Downloaded frontend-${config.frontendFramework}-${config.ui}-${config.variant}`);
|
|
1462
871
|
}
|
|
1463
872
|
await copyRootFiles(REPO, absolutePath, config);
|
|
1464
873
|
spinner2.message("Downloaded configuration files");
|
|
@@ -1467,16 +876,6 @@ async function generateProject(config) {
|
|
|
1467
876
|
spinner2.stop("Download failed");
|
|
1468
877
|
throw error;
|
|
1469
878
|
}
|
|
1470
|
-
const deselectedFeatures = ALL_FEATURES.filter((f) => !config.features.includes(f));
|
|
1471
|
-
if (deselectedFeatures.length > 0) {
|
|
1472
|
-
spinner2.start("Removing deselected feature files...");
|
|
1473
|
-
try {
|
|
1474
|
-
await removeDeselectedFeatures(absolutePath, config, deselectedFeatures);
|
|
1475
|
-
spinner2.stop(`Removed ${deselectedFeatures.length} deselected feature(s)`);
|
|
1476
|
-
} catch (error) {
|
|
1477
|
-
spinner2.stop("Feature removal had warnings");
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
879
|
spinner2.start("Updating configuration files...");
|
|
1481
880
|
try {
|
|
1482
881
|
await updateFolderReferences(absolutePath, config);
|
|
@@ -1521,48 +920,6 @@ async function generateProject(config) {
|
|
|
1521
920
|
await createAppSettingsFromExample(absolutePath, config);
|
|
1522
921
|
}
|
|
1523
922
|
}
|
|
1524
|
-
async function removeDeselectedFeatures(projectPath, config, deselectedFeatures) {
|
|
1525
|
-
if (config.projectType !== "frontend") {
|
|
1526
|
-
const backendMap = getBackendFileMap(config.backend, config.architecture);
|
|
1527
|
-
let backendDir;
|
|
1528
|
-
if (config.projectType === "fullstack") {
|
|
1529
|
-
backendDir = path5.join(projectPath, "backend");
|
|
1530
|
-
} else {
|
|
1531
|
-
backendDir = config.placeInRoot ? projectPath : path5.join(projectPath, "backend");
|
|
1532
|
-
}
|
|
1533
|
-
for (const feature of deselectedFeatures) {
|
|
1534
|
-
const featureMap = backendMap[feature];
|
|
1535
|
-
if (featureMap) {
|
|
1536
|
-
for (const filePath of featureMap.backend) {
|
|
1537
|
-
const fullPath = path5.join(backendDir, filePath);
|
|
1538
|
-
if (fs5.existsSync(fullPath)) {
|
|
1539
|
-
fs5.rmSync(fullPath, { recursive: true, force: true });
|
|
1540
|
-
}
|
|
1541
|
-
}
|
|
1542
|
-
}
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
if (config.projectType !== "backend") {
|
|
1546
|
-
const frontendMap = getFrontendFileMap(config.frontendFramework);
|
|
1547
|
-
let frontendDir;
|
|
1548
|
-
if (config.projectType === "fullstack") {
|
|
1549
|
-
frontendDir = path5.join(projectPath, "frontend");
|
|
1550
|
-
} else {
|
|
1551
|
-
frontendDir = config.placeInRoot ? projectPath : path5.join(projectPath, "frontend");
|
|
1552
|
-
}
|
|
1553
|
-
for (const feature of deselectedFeatures) {
|
|
1554
|
-
const featurePaths = frontendMap[feature];
|
|
1555
|
-
if (featurePaths) {
|
|
1556
|
-
for (const filePath of featurePaths) {
|
|
1557
|
-
const fullPath = path5.join(frontendDir, filePath);
|
|
1558
|
-
if (fs5.existsSync(fullPath)) {
|
|
1559
|
-
fs5.rmSync(fullPath, { recursive: true, force: true });
|
|
1560
|
-
}
|
|
1561
|
-
}
|
|
1562
|
-
}
|
|
1563
|
-
}
|
|
1564
|
-
}
|
|
1565
|
-
}
|
|
1566
923
|
function cleanupFullstackDockerFiles(projectPath) {
|
|
1567
924
|
const filesToDelete = [
|
|
1568
925
|
"backend/Dockerfile",
|
|
@@ -1727,7 +1084,7 @@ async function main() {
|
|
|
1727
1084
|
projectName: cliArgs.projectName,
|
|
1728
1085
|
installDeps: cliArgs.install || false,
|
|
1729
1086
|
placeInRoot: cliArgs.root || false,
|
|
1730
|
-
|
|
1087
|
+
variant: cliArgs.variant || "full"
|
|
1731
1088
|
};
|
|
1732
1089
|
} else {
|
|
1733
1090
|
const result = await runInteractivePrompts(cliArgs);
|
|
@@ -1763,8 +1120,9 @@ ${pc3.bold("Options:")}
|
|
|
1763
1120
|
${pc3.yellow("-u, --ui")} UI library: vuetify, primevue (Vue) | mui, primereact (React)
|
|
1764
1121
|
${pc3.yellow("-n, --name")} Project namespace (Company.Project format, .NET/Spring only)
|
|
1765
1122
|
${pc3.yellow("-r, --root")} Place files in project root ${pc3.gray("(backend/frontend-only)")}
|
|
1766
|
-
${pc3.yellow("--
|
|
1767
|
-
|
|
1123
|
+
${pc3.yellow("-V, --variant")} Template variant: full, minimal ${pc3.gray("(default: full)")}
|
|
1124
|
+
full: All features (user management, departments, dashboard)
|
|
1125
|
+
minimal: Auth, files, audit logs, notifications only
|
|
1768
1126
|
${pc3.yellow("-i, --install")} Install dependencies after creation
|
|
1769
1127
|
${pc3.yellow("-h, --help")} Show this help message
|
|
1770
1128
|
${pc3.yellow("-v, --version")} Show version number
|
|
@@ -1776,8 +1134,8 @@ ${pc3.bold("Examples:")}
|
|
|
1776
1134
|
${pc3.gray("# Create fullstack project with .NET backend")}
|
|
1777
1135
|
npm create apptemplate@latest my-app -b dotnet -n "MyCompany.MyApp" -i
|
|
1778
1136
|
|
|
1779
|
-
${pc3.gray("# Create backend-only project
|
|
1780
|
-
npm create apptemplate@latest my-api -t backend -b spring -n "MyCompany.MyApi"
|
|
1137
|
+
${pc3.gray("# Create minimal backend-only project (no user management)")}
|
|
1138
|
+
npm create apptemplate@latest my-api -t backend -b spring -n "MyCompany.MyApi" -V minimal
|
|
1781
1139
|
|
|
1782
1140
|
${pc3.gray("# Create frontend-only project with PrimeVue")}
|
|
1783
1141
|
npm create apptemplate@latest my-spa -t frontend -u primevue
|