@atlashub/smartstack-mcp 1.10.0 → 1.13.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.
- package/dist/index.js +209 -129
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/migrations/seed-permissions.cs.hbs +0 -108
package/dist/index.js
CHANGED
|
@@ -1822,6 +1822,10 @@ var scaffoldExtensionTool = {
|
|
|
1822
1822
|
type: "boolean",
|
|
1823
1823
|
description: "For feature type: generate repository pattern"
|
|
1824
1824
|
},
|
|
1825
|
+
withSeedData: {
|
|
1826
|
+
type: "boolean",
|
|
1827
|
+
description: "For entity type: generate centralized SeedData file in Seeding/Data/{Domain}/"
|
|
1828
|
+
},
|
|
1825
1829
|
entityProperties: {
|
|
1826
1830
|
type: "array",
|
|
1827
1831
|
items: {
|
|
@@ -2346,6 +2350,119 @@ public class {{name}}Configuration : IEntityTypeConfiguration<{{name}}>
|
|
|
2346
2350
|
result.instructions.push("- CreatedAt, UpdatedAt, CreatedBy, UpdatedBy (audit)");
|
|
2347
2351
|
result.instructions.push("- IsDeleted, DeletedAt, DeletedBy (soft delete)");
|
|
2348
2352
|
result.instructions.push("- RowVersion (concurrency)");
|
|
2353
|
+
if (options?.withSeedData) {
|
|
2354
|
+
result.instructions.push("");
|
|
2355
|
+
result.instructions.push("### Seed Data");
|
|
2356
|
+
await scaffoldSeedData(name, options, structure, config, result, dryRun);
|
|
2357
|
+
}
|
|
2358
|
+
}
|
|
2359
|
+
async function scaffoldSeedData(name, options, structure, config, result, dryRun = false) {
|
|
2360
|
+
const tablePrefix = options?.tablePrefix || "ref_";
|
|
2361
|
+
const domainMap = {
|
|
2362
|
+
"auth_": "Authorization",
|
|
2363
|
+
"nav_": "Navigation",
|
|
2364
|
+
"usr_": "User",
|
|
2365
|
+
"wkf_": "Communications",
|
|
2366
|
+
"cfg_": "Configuration",
|
|
2367
|
+
"ai_": "AI",
|
|
2368
|
+
"entra_": "Entra",
|
|
2369
|
+
"ref_": "Reference",
|
|
2370
|
+
"support_": "Support",
|
|
2371
|
+
"loc_": "Localization"
|
|
2372
|
+
};
|
|
2373
|
+
const domain = options?.seedDataDomain || domainMap[tablePrefix] || "Reference";
|
|
2374
|
+
const isSystemEntity = options?.isSystemEntity || false;
|
|
2375
|
+
const seedDataTemplate = `using SmartStack.Domain.{{domainNamespace}};
|
|
2376
|
+
|
|
2377
|
+
namespace SmartStack.Infrastructure.Persistence.Seeding.Data.{{domain}};
|
|
2378
|
+
|
|
2379
|
+
/// <summary>
|
|
2380
|
+
/// Donnees seed pour {{name}}.
|
|
2381
|
+
/// Centralise les IDs et donnees d'initialisation.
|
|
2382
|
+
/// </summary>
|
|
2383
|
+
public static class {{name}}SeedData
|
|
2384
|
+
{
|
|
2385
|
+
// ============================================================
|
|
2386
|
+
// IDs - Documenter chaque ID avec son role
|
|
2387
|
+
// ============================================================
|
|
2388
|
+
|
|
2389
|
+
/// <summary>ID exemple - A remplacer par vos IDs</summary>
|
|
2390
|
+
public static readonly Guid ExampleId = Guid.Parse("{{exampleGuid}}");
|
|
2391
|
+
|
|
2392
|
+
// ============================================================
|
|
2393
|
+
// CODES / CONSTANTS
|
|
2394
|
+
// ============================================================
|
|
2395
|
+
|
|
2396
|
+
public const string ExampleCode = "example";
|
|
2397
|
+
|
|
2398
|
+
// ============================================================
|
|
2399
|
+
// SEED DATA
|
|
2400
|
+
// ============================================================
|
|
2401
|
+
|
|
2402
|
+
/// <summary>
|
|
2403
|
+
/// Retourne toutes les donnees seed pour {{name}}.
|
|
2404
|
+
/// Appel\xE9 depuis {{name}}Configuration.HasData()
|
|
2405
|
+
/// </summary>
|
|
2406
|
+
public static object[] GetSeedData()
|
|
2407
|
+
{
|
|
2408
|
+
var seedDate = SeedConstants.SeedDate;
|
|
2409
|
+
|
|
2410
|
+
return new object[]
|
|
2411
|
+
{
|
|
2412
|
+
// Exemple - A remplacer par vos donnees
|
|
2413
|
+
new
|
|
2414
|
+
{
|
|
2415
|
+
Id = ExampleId,
|
|
2416
|
+
{{#unless isSystemEntity}}
|
|
2417
|
+
TenantId = (Guid?)null, // Seed data systeme sans tenant
|
|
2418
|
+
{{/unless}}
|
|
2419
|
+
Code = ExampleCode,
|
|
2420
|
+
// TODO: Ajouter les proprietes specifiques
|
|
2421
|
+
IsDeleted = false,
|
|
2422
|
+
CreatedAt = seedDate
|
|
2423
|
+
}
|
|
2424
|
+
};
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2427
|
+
`;
|
|
2428
|
+
const exampleGuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
2429
|
+
const r = Math.random() * 16 | 0;
|
|
2430
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
2431
|
+
return v.toString(16);
|
|
2432
|
+
});
|
|
2433
|
+
const context = {
|
|
2434
|
+
name,
|
|
2435
|
+
domain,
|
|
2436
|
+
domainNamespace: domain,
|
|
2437
|
+
isSystemEntity,
|
|
2438
|
+
exampleGuid
|
|
2439
|
+
};
|
|
2440
|
+
const seedDataContent = Handlebars.compile(seedDataTemplate)(context);
|
|
2441
|
+
const projectRoot = config.smartstack.projectPath;
|
|
2442
|
+
const infraPath = structure.infrastructure || path8.join(projectRoot, "Infrastructure");
|
|
2443
|
+
const seedDataPath = path8.join(infraPath, "Persistence", "Seeding", "Data", domain);
|
|
2444
|
+
const seedDataFilePath = path8.join(seedDataPath, `${name}SeedData.cs`);
|
|
2445
|
+
validatePathSecurity(seedDataFilePath, projectRoot);
|
|
2446
|
+
if (!dryRun) {
|
|
2447
|
+
await ensureDirectory(seedDataPath);
|
|
2448
|
+
await writeText(seedDataFilePath, seedDataContent);
|
|
2449
|
+
}
|
|
2450
|
+
result.files.push({ path: seedDataFilePath, content: seedDataContent, type: "created" });
|
|
2451
|
+
result.instructions.push(`SeedData file generated in Seeding/Data/${domain}/`);
|
|
2452
|
+
result.instructions.push("");
|
|
2453
|
+
result.instructions.push("Update your Configuration to use centralized SeedData:");
|
|
2454
|
+
result.instructions.push("```csharp");
|
|
2455
|
+
result.instructions.push(`// In ${name}Configuration.cs`);
|
|
2456
|
+
result.instructions.push(`using SmartStack.Infrastructure.Persistence.Seeding.Data.${domain};`);
|
|
2457
|
+
result.instructions.push("");
|
|
2458
|
+
result.instructions.push(`builder.HasData(${name}SeedData.GetSeedData());`);
|
|
2459
|
+
result.instructions.push("```");
|
|
2460
|
+
result.instructions.push("");
|
|
2461
|
+
result.instructions.push("Pattern to follow:");
|
|
2462
|
+
result.instructions.push("1. Define public static readonly Guid IDs");
|
|
2463
|
+
result.instructions.push("2. Define const string codes");
|
|
2464
|
+
result.instructions.push("3. Implement GetSeedData() returning object[]");
|
|
2465
|
+
result.instructions.push("4. Reference other SeedData IDs for foreign keys");
|
|
2349
2466
|
}
|
|
2350
2467
|
async function scaffoldController(name, options, structure, config, result, dryRun = false) {
|
|
2351
2468
|
const namespace = options?.namespace || `${config.conventions.namespaces.api}.Controllers`;
|
|
@@ -3658,7 +3775,7 @@ async function handleSuggestMigration(args, config) {
|
|
|
3658
3775
|
async function findExistingMigrations(structure, config, context) {
|
|
3659
3776
|
const migrations = [];
|
|
3660
3777
|
const infraPath = structure.infrastructure || path10.join(config.smartstack.projectPath, "Infrastructure");
|
|
3661
|
-
const migrationsPath = path10.join(infraPath, "Migrations");
|
|
3778
|
+
const migrationsPath = path10.join(infraPath, "Persistence", "Migrations");
|
|
3662
3779
|
try {
|
|
3663
3780
|
const migrationFiles = await findFiles("*.cs", { cwd: migrationsPath });
|
|
3664
3781
|
const migrationPattern = /^(\w+)_v(\d+\.\d+\.\d+)_(\d+)_(\w+)\.cs$/;
|
|
@@ -3705,7 +3822,6 @@ function compareVersions2(a, b) {
|
|
|
3705
3822
|
}
|
|
3706
3823
|
|
|
3707
3824
|
// src/tools/generate-permissions.ts
|
|
3708
|
-
import Handlebars2 from "handlebars";
|
|
3709
3825
|
import path11 from "path";
|
|
3710
3826
|
var HTTP_METHOD_TO_ACTION = {
|
|
3711
3827
|
"GET": "read",
|
|
@@ -3722,17 +3838,21 @@ var generatePermissionsTool = {
|
|
|
3722
3838
|
name: "generate_permissions",
|
|
3723
3839
|
description: `Generate RBAC permissions for SmartStack controllers.
|
|
3724
3840
|
|
|
3725
|
-
|
|
3841
|
+
Analyzes NavRoute attributes and outputs HasData() C# code to add to PermissionConfiguration.cs.
|
|
3842
|
+
|
|
3843
|
+
IMPORTANT: This tool does NOT generate migrations with raw SQL (forbidden by SmartStack conventions).
|
|
3844
|
+
Instead, it outputs HasData() code that must be manually added to the Configuration file.
|
|
3726
3845
|
|
|
3727
3846
|
Example:
|
|
3728
3847
|
navRoute: "platform.administration.entra"
|
|
3729
|
-
|
|
3848
|
+
Outputs HasData() code for:
|
|
3849
|
+
- platform.administration.entra.*
|
|
3730
3850
|
- platform.administration.entra.read
|
|
3731
3851
|
- platform.administration.entra.create
|
|
3732
3852
|
- platform.administration.entra.update
|
|
3733
3853
|
- platform.administration.entra.delete
|
|
3734
3854
|
|
|
3735
|
-
|
|
3855
|
+
After adding to PermissionConfiguration.cs, run: dotnet ef migrations add <MigrationName>`,
|
|
3736
3856
|
inputSchema: {
|
|
3737
3857
|
type: "object",
|
|
3738
3858
|
properties: {
|
|
@@ -3750,15 +3870,10 @@ Can also generate EF Core migration to seed permissions in database.`,
|
|
|
3750
3870
|
default: true,
|
|
3751
3871
|
description: "Include standard CRUD actions (read, create, update, delete)"
|
|
3752
3872
|
},
|
|
3753
|
-
|
|
3873
|
+
includeWildcard: {
|
|
3754
3874
|
type: "boolean",
|
|
3755
3875
|
default: true,
|
|
3756
|
-
description: "
|
|
3757
|
-
},
|
|
3758
|
-
dryRun: {
|
|
3759
|
-
type: "boolean",
|
|
3760
|
-
default: false,
|
|
3761
|
-
description: "Preview without writing files or creating migration"
|
|
3876
|
+
description: "Include wildcard permission (e.g., personal.myspace.tenants.*)"
|
|
3762
3877
|
}
|
|
3763
3878
|
}
|
|
3764
3879
|
}
|
|
@@ -3769,8 +3884,7 @@ async function handleGeneratePermissions(args, config) {
|
|
|
3769
3884
|
navRoute: args.navRoute,
|
|
3770
3885
|
actions: args.actions || [],
|
|
3771
3886
|
includeStandardActions: args.includeStandardActions !== false,
|
|
3772
|
-
|
|
3773
|
-
dryRun: args.dryRun === true
|
|
3887
|
+
includeWildcard: args.includeWildcard !== false
|
|
3774
3888
|
};
|
|
3775
3889
|
const structure = await findSmartStackStructure(config.smartstack.projectPath);
|
|
3776
3890
|
if (!structure) {
|
|
@@ -3782,16 +3896,17 @@ async function handleGeneratePermissions(args, config) {
|
|
|
3782
3896
|
permissions = generatePermissionsForNavRoute(
|
|
3783
3897
|
options.navRoute,
|
|
3784
3898
|
options.actions || [],
|
|
3785
|
-
options.includeStandardActions || false
|
|
3899
|
+
options.includeStandardActions || false,
|
|
3900
|
+
options.includeWildcard || false
|
|
3786
3901
|
);
|
|
3787
|
-
report = `## Permissions
|
|
3902
|
+
report = `## Permissions for NavRoute: ${options.navRoute}
|
|
3788
3903
|
|
|
3789
3904
|
`;
|
|
3790
3905
|
report += formatPermissionsReport(permissions);
|
|
3791
3906
|
} else {
|
|
3792
3907
|
const scannedPermissions = await scanControllersForPermissions(structure.api || structure.root);
|
|
3793
3908
|
permissions = scannedPermissions;
|
|
3794
|
-
report = `## Permissions
|
|
3909
|
+
report = `## Permissions from All Controllers
|
|
3795
3910
|
|
|
3796
3911
|
`;
|
|
3797
3912
|
report += `Total controllers scanned: ${getUniqueNavRouteCount(permissions)}
|
|
@@ -3801,53 +3916,51 @@ async function handleGeneratePermissions(args, config) {
|
|
|
3801
3916
|
`;
|
|
3802
3917
|
report += formatPermissionsReport(permissions);
|
|
3803
3918
|
}
|
|
3804
|
-
|
|
3805
|
-
const migrationResult = await generatePermissionMigration(
|
|
3806
|
-
structure.api || structure.root,
|
|
3807
|
-
permissions,
|
|
3808
|
-
config
|
|
3809
|
-
);
|
|
3810
|
-
report += `
|
|
3919
|
+
report += `
|
|
3811
3920
|
|
|
3812
|
-
##
|
|
3921
|
+
## HasData() Code for PermissionConfiguration.cs
|
|
3813
3922
|
|
|
3814
3923
|
`;
|
|
3815
|
-
|
|
3924
|
+
report += `\u26A0\uFE0F **IMPORTANT**: Do NOT use migrationBuilder.Sql() - it's forbidden by SmartStack conventions.
|
|
3816
3925
|
`;
|
|
3817
|
-
|
|
3926
|
+
report += `Add this code to \`PermissionConfiguration.cs\` in the HasData() section, then create a migration.
|
|
3818
3927
|
|
|
3819
3928
|
`;
|
|
3820
|
-
|
|
3929
|
+
report += generateHasDataCode(permissions, options.navRoute || "custom");
|
|
3930
|
+
report += `
|
|
3931
|
+
|
|
3932
|
+
### Next Steps
|
|
3821
3933
|
|
|
3822
3934
|
`;
|
|
3823
|
-
|
|
3824
|
-
`;
|
|
3825
|
-
report += `2. Run: \`dotnet ef database update\`
|
|
3935
|
+
report += `1. Add the module ID variable in GetSeedData() method
|
|
3826
3936
|
`;
|
|
3827
|
-
|
|
3937
|
+
report += `2. Add the HasData entries to the return array
|
|
3828
3938
|
`;
|
|
3829
|
-
|
|
3830
|
-
report += `
|
|
3831
|
-
|
|
3832
|
-
## Dry Run Mode
|
|
3833
|
-
|
|
3939
|
+
report += `3. Run: \`dotnet ef migrations add <MigrationName> -o Persistence/Migrations\`
|
|
3834
3940
|
`;
|
|
3835
|
-
|
|
3941
|
+
report += `4. Run: \`dotnet ef database update\`
|
|
3836
3942
|
`;
|
|
3837
|
-
}
|
|
3838
3943
|
return report;
|
|
3839
3944
|
} catch (error) {
|
|
3840
3945
|
logger.error("Error generating permissions:", error);
|
|
3841
3946
|
throw error;
|
|
3842
3947
|
}
|
|
3843
3948
|
}
|
|
3844
|
-
function generatePermissionsForNavRoute(navRoute, customActions, includeStandardActions) {
|
|
3949
|
+
function generatePermissionsForNavRoute(navRoute, customActions, includeStandardActions, includeWildcard = true) {
|
|
3845
3950
|
const permissions = [];
|
|
3846
3951
|
const parts = navRoute.split(".");
|
|
3847
3952
|
const context = parts[0];
|
|
3848
3953
|
if (parts.length < 3) {
|
|
3849
3954
|
throw new Error(`Invalid NavRoute format: ${navRoute}. Expected format: context.application.module`);
|
|
3850
3955
|
}
|
|
3956
|
+
if (includeWildcard) {
|
|
3957
|
+
permissions.push({
|
|
3958
|
+
code: `${navRoute}.*`,
|
|
3959
|
+
name: formatPermissionName(navRoute, "Full Access"),
|
|
3960
|
+
description: `Full ${parts[parts.length - 1]} management`,
|
|
3961
|
+
category: context
|
|
3962
|
+
});
|
|
3963
|
+
}
|
|
3851
3964
|
const actions = includeStandardActions ? [...STANDARD_ACTIONS, ...customActions] : customActions;
|
|
3852
3965
|
for (const action of actions) {
|
|
3853
3966
|
const code = `${navRoute}.${action}`;
|
|
@@ -3986,87 +4099,54 @@ function getUniqueNavRouteCount(permissions) {
|
|
|
3986
4099
|
);
|
|
3987
4100
|
return navRoutes.size;
|
|
3988
4101
|
}
|
|
3989
|
-
|
|
3990
|
-
const
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
try {
|
|
3998
|
-
template = await readText(templatePath);
|
|
3999
|
-
} catch {
|
|
4000
|
-
template = getSeedPermissionsTemplate();
|
|
4001
|
-
}
|
|
4002
|
-
const handlebars = Handlebars2.create();
|
|
4003
|
-
const compiled = handlebars.compile(template);
|
|
4004
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:T.]/g, "").slice(0, 14);
|
|
4005
|
-
const migrationName = `SeedPermissions_${timestamp}`;
|
|
4006
|
-
const content = compiled({
|
|
4007
|
-
migrationName,
|
|
4008
|
-
permissions,
|
|
4009
|
-
timestamp
|
|
4010
|
-
});
|
|
4011
|
-
const migrationsPath = path11.join(
|
|
4012
|
-
backendRoot,
|
|
4013
|
-
"Infrastructure",
|
|
4014
|
-
"Data",
|
|
4015
|
-
"Migrations",
|
|
4016
|
-
"Core"
|
|
4017
|
-
);
|
|
4018
|
-
await ensureDirectory(migrationsPath);
|
|
4019
|
-
const filePath = path11.join(migrationsPath, `${migrationName}.cs`);
|
|
4020
|
-
validatePathSecurity(filePath, config.smartstack.projectPath);
|
|
4021
|
-
await writeText(filePath, content);
|
|
4022
|
-
logger.info(`Generated permission migration: ${filePath}`);
|
|
4023
|
-
return {
|
|
4024
|
-
filePath,
|
|
4025
|
-
migrationName
|
|
4026
|
-
};
|
|
4027
|
-
}
|
|
4028
|
-
function getSeedPermissionsTemplate() {
|
|
4029
|
-
return `using Microsoft.EntityFrameworkCore.Migrations;
|
|
4030
|
-
|
|
4031
|
-
namespace SmartStack.Infrastructure.Data.Migrations.Core;
|
|
4102
|
+
function generateHasDataCode(permissions, navRoute) {
|
|
4103
|
+
const parts = navRoute.split(".");
|
|
4104
|
+
const moduleName = parts.length >= 3 ? parts[parts.length - 1] : "custom";
|
|
4105
|
+
const moduleVarName = `${moduleName}ModuleId`;
|
|
4106
|
+
let code = "```csharp\n";
|
|
4107
|
+
code += `// 1. Add module ID variable (get from NavigationModuleSeedData.cs)
|
|
4108
|
+
`;
|
|
4109
|
+
code += `var ${moduleVarName} = Guid.Parse("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"); // TODO: Replace with actual ID
|
|
4032
4110
|
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
{
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
VALUES (
|
|
4048
|
-
NEWID(),
|
|
4049
|
-
'{{code}}',
|
|
4050
|
-
'{{name}}',
|
|
4051
|
-
'{{description}}',
|
|
4052
|
-
0,
|
|
4053
|
-
GETUTCDATE(),
|
|
4054
|
-
GETUTCDATE()
|
|
4055
|
-
);
|
|
4056
|
-
END
|
|
4057
|
-
");
|
|
4058
|
-
{{/each}}
|
|
4059
|
-
}
|
|
4060
|
-
|
|
4061
|
-
protected override void Down(MigrationBuilder migrationBuilder)
|
|
4062
|
-
{
|
|
4063
|
-
// Remove seeded permissions
|
|
4064
|
-
{{#each permissions}}
|
|
4065
|
-
migrationBuilder.Sql(@"DELETE FROM core.auth_Permissions WHERE Code = '{{code}}'");
|
|
4066
|
-
{{/each}}
|
|
4111
|
+
`;
|
|
4112
|
+
code += `// 2. Add these entries to the HasData() return array:
|
|
4113
|
+
`;
|
|
4114
|
+
for (const perm of permissions) {
|
|
4115
|
+
const isWildcard = perm.code.endsWith(".*");
|
|
4116
|
+
const action = perm.code.split(".").pop();
|
|
4117
|
+
const guidPlaceholder = generatePlaceholderGuid();
|
|
4118
|
+
if (isWildcard) {
|
|
4119
|
+
code += `new { Id = Guid.Parse("${guidPlaceholder}"), Path = "${perm.code}", Level = PermissionLevel.Module, IsWildcard = true, ModuleId = ${moduleVarName}, Description = "${perm.description}", CreatedAt = seedDate },
|
|
4120
|
+
`;
|
|
4121
|
+
} else {
|
|
4122
|
+
const actionEnum = getActionEnum(action || "read");
|
|
4123
|
+
code += `new { Id = Guid.Parse("${guidPlaceholder}"), Path = "${perm.code}", Level = PermissionLevel.Module, Action = PermissionAction.${actionEnum}, IsWildcard = false, ModuleId = ${moduleVarName}, Description = "${perm.description}", CreatedAt = seedDate },
|
|
4124
|
+
`;
|
|
4067
4125
|
}
|
|
4068
|
-
}
|
|
4126
|
+
}
|
|
4127
|
+
code += "```\n";
|
|
4128
|
+
code += "\n\u26A0\uFE0F **IMPORTANT**: Replace all GUIDs with randomly generated ones using:\n";
|
|
4129
|
+
code += "```powershell\n";
|
|
4130
|
+
code += `1..${permissions.length} | ForEach-Object { [guid]::NewGuid().ToString() }
|
|
4069
4131
|
`;
|
|
4132
|
+
code += "```\n";
|
|
4133
|
+
return code;
|
|
4134
|
+
}
|
|
4135
|
+
function generatePlaceholderGuid() {
|
|
4136
|
+
return "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX";
|
|
4137
|
+
}
|
|
4138
|
+
function getActionEnum(action) {
|
|
4139
|
+
const actionMap = {
|
|
4140
|
+
"read": "Read",
|
|
4141
|
+
"create": "Create",
|
|
4142
|
+
"update": "Update",
|
|
4143
|
+
"delete": "Delete",
|
|
4144
|
+
"assign": "Assign",
|
|
4145
|
+
"execute": "Execute",
|
|
4146
|
+
"export": "Export",
|
|
4147
|
+
"import": "Import"
|
|
4148
|
+
};
|
|
4149
|
+
return actionMap[action.toLowerCase()] || action.charAt(0).toUpperCase() + action.slice(1);
|
|
4070
4150
|
}
|
|
4071
4151
|
async function readDirectoryRecursive(dir) {
|
|
4072
4152
|
const files = [];
|
|
@@ -4086,7 +4166,7 @@ async function readDirectoryRecursive(dir) {
|
|
|
4086
4166
|
}
|
|
4087
4167
|
|
|
4088
4168
|
// src/tools/scaffold-tests.ts
|
|
4089
|
-
import
|
|
4169
|
+
import Handlebars2 from "handlebars";
|
|
4090
4170
|
import path12 from "path";
|
|
4091
4171
|
var scaffoldTestsTool = {
|
|
4092
4172
|
name: "scaffold_tests",
|
|
@@ -4166,15 +4246,15 @@ var scaffoldTestsTool = {
|
|
|
4166
4246
|
required: ["target", "name"]
|
|
4167
4247
|
}
|
|
4168
4248
|
};
|
|
4169
|
-
|
|
4249
|
+
Handlebars2.registerHelper("pascalCase", (str) => {
|
|
4170
4250
|
if (!str) return "";
|
|
4171
4251
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
4172
4252
|
});
|
|
4173
|
-
|
|
4253
|
+
Handlebars2.registerHelper("camelCase", (str) => {
|
|
4174
4254
|
if (!str) return "";
|
|
4175
4255
|
return str.charAt(0).toLowerCase() + str.slice(1);
|
|
4176
4256
|
});
|
|
4177
|
-
|
|
4257
|
+
Handlebars2.registerHelper("unless", function(conditional, options) {
|
|
4178
4258
|
if (!conditional) {
|
|
4179
4259
|
return options.fn(this);
|
|
4180
4260
|
}
|
|
@@ -5516,7 +5596,7 @@ async function scaffoldEntityTests(name, options, testTypes, structure, config,
|
|
|
5516
5596
|
...options
|
|
5517
5597
|
};
|
|
5518
5598
|
if (testTypes.includes("unit")) {
|
|
5519
|
-
const content =
|
|
5599
|
+
const content = Handlebars2.compile(entityTestTemplate)(context);
|
|
5520
5600
|
const testPath = path12.join(structure.root, "Tests", "Unit", "Domain", `${name}Tests.cs`);
|
|
5521
5601
|
validatePathSecurity(testPath, structure.root);
|
|
5522
5602
|
if (!dryRun) {
|
|
@@ -5530,7 +5610,7 @@ async function scaffoldEntityTests(name, options, testTypes, structure, config,
|
|
|
5530
5610
|
});
|
|
5531
5611
|
}
|
|
5532
5612
|
if (testTypes.includes("security")) {
|
|
5533
|
-
const securityContent =
|
|
5613
|
+
const securityContent = Handlebars2.compile(securityTestTemplate)({
|
|
5534
5614
|
...context,
|
|
5535
5615
|
nameLower: name.charAt(0).toLowerCase() + name.slice(1),
|
|
5536
5616
|
apiNamespace: config.conventions.namespaces.api
|
|
@@ -5562,7 +5642,7 @@ async function scaffoldServiceTests(name, options, testTypes, structure, config,
|
|
|
5562
5642
|
...options
|
|
5563
5643
|
};
|
|
5564
5644
|
if (testTypes.includes("unit")) {
|
|
5565
|
-
const content =
|
|
5645
|
+
const content = Handlebars2.compile(serviceTestTemplate)(context);
|
|
5566
5646
|
const testPath = path12.join(structure.root, "Tests", "Unit", "Services", `${name}ServiceTests.cs`);
|
|
5567
5647
|
validatePathSecurity(testPath, structure.root);
|
|
5568
5648
|
if (!dryRun) {
|
|
@@ -5592,7 +5672,7 @@ async function scaffoldControllerTests(name, options, testTypes, structure, conf
|
|
|
5592
5672
|
...options
|
|
5593
5673
|
};
|
|
5594
5674
|
if (testTypes.includes("integration")) {
|
|
5595
|
-
const content =
|
|
5675
|
+
const content = Handlebars2.compile(controllerTestTemplate)(context);
|
|
5596
5676
|
const testPath = path12.join(structure.root, "Tests", "Integration", "Controllers", `${name}ControllerTests.cs`);
|
|
5597
5677
|
validatePathSecurity(testPath, structure.root);
|
|
5598
5678
|
if (!dryRun) {
|
|
@@ -5606,7 +5686,7 @@ async function scaffoldControllerTests(name, options, testTypes, structure, conf
|
|
|
5606
5686
|
});
|
|
5607
5687
|
}
|
|
5608
5688
|
if (testTypes.includes("security")) {
|
|
5609
|
-
const securityContent =
|
|
5689
|
+
const securityContent = Handlebars2.compile(securityTestTemplate)(context);
|
|
5610
5690
|
const securityPath = path12.join(structure.root, "Tests", "Security", `${name}SecurityTests.cs`);
|
|
5611
5691
|
validatePathSecurity(securityPath, structure.root);
|
|
5612
5692
|
if (!dryRun) {
|
|
@@ -5631,7 +5711,7 @@ async function scaffoldValidatorTests(name, options, testTypes, structure, confi
|
|
|
5631
5711
|
...options
|
|
5632
5712
|
};
|
|
5633
5713
|
if (testTypes.includes("unit")) {
|
|
5634
|
-
const content =
|
|
5714
|
+
const content = Handlebars2.compile(validatorTestTemplate)(context);
|
|
5635
5715
|
const testPath = path12.join(structure.root, "Tests", "Unit", "Validators", `${name}ValidatorTests.cs`);
|
|
5636
5716
|
validatePathSecurity(testPath, structure.root);
|
|
5637
5717
|
if (!dryRun) {
|
|
@@ -5658,7 +5738,7 @@ async function scaffoldRepositoryTests(name, options, testTypes, structure, conf
|
|
|
5658
5738
|
...options
|
|
5659
5739
|
};
|
|
5660
5740
|
if (testTypes.includes("integration")) {
|
|
5661
|
-
const content =
|
|
5741
|
+
const content = Handlebars2.compile(repositoryTestTemplate)(context);
|
|
5662
5742
|
const testPath = path12.join(structure.root, "Tests", "Integration", "Repositories", `${name}RepositoryTests.cs`);
|
|
5663
5743
|
validatePathSecurity(testPath, structure.root);
|
|
5664
5744
|
if (!dryRun) {
|