@atlashub/smartstack-mcp 1.21.0 → 1.22.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 +72 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2438,6 +2438,27 @@ Handlebars.registerHelper("camelCase", (str) => {
|
|
|
2438
2438
|
Handlebars.registerHelper("kebabCase", (str) => {
|
|
2439
2439
|
return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
2440
2440
|
});
|
|
2441
|
+
function resolveHierarchy(navRoute) {
|
|
2442
|
+
if (!navRoute) {
|
|
2443
|
+
return { context: "", application: "", module: "", domainPath: "", infraPath: "", controllerArea: "" };
|
|
2444
|
+
}
|
|
2445
|
+
const segments = navRoute.split(".");
|
|
2446
|
+
const toPascal = (s) => s.split("-").map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join("");
|
|
2447
|
+
const context = segments[0] ? toPascal(segments[0]) : "";
|
|
2448
|
+
const application = segments[1] ? toPascal(segments[1]) : "";
|
|
2449
|
+
const module = segments[2] ? toPascal(segments[2]) : segments[1] ? toPascal(segments[1]) : "";
|
|
2450
|
+
let domainPath = "";
|
|
2451
|
+
if (segments.length >= 3) {
|
|
2452
|
+
domainPath = path8.join(context, application, module);
|
|
2453
|
+
} else if (segments.length === 2) {
|
|
2454
|
+
domainPath = path8.join(context, module);
|
|
2455
|
+
} else if (segments.length === 1) {
|
|
2456
|
+
domainPath = context;
|
|
2457
|
+
}
|
|
2458
|
+
const infraPath = module || "";
|
|
2459
|
+
const controllerArea = context;
|
|
2460
|
+
return { context, application, module, domainPath, infraPath, controllerArea };
|
|
2461
|
+
}
|
|
2441
2462
|
async function handleScaffoldExtension(args, config) {
|
|
2442
2463
|
const input = ScaffoldExtensionInputSchema.parse(args);
|
|
2443
2464
|
const dryRun = input.options?.dryRun || false;
|
|
@@ -2582,17 +2603,21 @@ async function scaffoldFeature(name, options, structure, config, result, dryRun
|
|
|
2582
2603
|
result.instructions.push(`${withRepository ? withValidation ? "5" : "4" : withValidation ? "4" : "3"}. Create migration: \`dotnet ef migrations add ${migrationPrefix}_vX.X.X_XXX_Add${name} --context ${dbContextName}\``);
|
|
2583
2604
|
result.instructions.push(`${withRepository ? withValidation ? "6" : "5" : withValidation ? "5" : "4"}. Run migration: \`dotnet ef database update --context ${dbContextName}\``);
|
|
2584
2605
|
if (!skipComponent) {
|
|
2585
|
-
|
|
2606
|
+
const featureHierarchy = resolveHierarchy(options?.navRoute);
|
|
2607
|
+
const featureComponentPath = featureHierarchy.context && featureHierarchy.module ? `@/components/${featureHierarchy.context.toLowerCase()}/${featureHierarchy.module.toLowerCase()}/${name}` : `./components/${name}`;
|
|
2608
|
+
result.instructions.push(`Import component: \`import { ${name} } from '${featureComponentPath}';\``);
|
|
2586
2609
|
}
|
|
2587
2610
|
}
|
|
2588
2611
|
async function scaffoldService(name, options, structure, config, result, dryRun = false) {
|
|
2589
|
-
const
|
|
2612
|
+
const hierarchy = resolveHierarchy(options?.navRoute);
|
|
2613
|
+
const interfaceNamespace = options?.namespace || `${config.conventions.namespaces.application}.Common.Interfaces`;
|
|
2614
|
+
const implNamespace = hierarchy.infraPath ? `${config.conventions.namespaces.infrastructure}.Services.${hierarchy.infraPath}` : `${config.conventions.namespaces.infrastructure}.Services`;
|
|
2590
2615
|
const methods = options?.methods || ["GetByIdAsync", "GetAllAsync", "CreateAsync", "UpdateAsync", "DeleteAsync"];
|
|
2591
2616
|
const interfaceTemplate = `using System.Threading;
|
|
2592
2617
|
using System.Threading.Tasks;
|
|
2593
2618
|
using System.Collections.Generic;
|
|
2594
2619
|
|
|
2595
|
-
namespace {{
|
|
2620
|
+
namespace {{interfaceNamespace}};
|
|
2596
2621
|
|
|
2597
2622
|
/// <summary>
|
|
2598
2623
|
/// Service interface for {{name}} operations
|
|
@@ -2613,7 +2638,7 @@ using System.Threading.Tasks;
|
|
|
2613
2638
|
using System.Collections.Generic;
|
|
2614
2639
|
using Microsoft.Extensions.Logging;
|
|
2615
2640
|
|
|
2616
|
-
namespace {{
|
|
2641
|
+
namespace {{implNamespace}};
|
|
2617
2642
|
|
|
2618
2643
|
/// <summary>
|
|
2619
2644
|
/// Service implementation for {{name}} operations
|
|
@@ -2643,19 +2668,22 @@ public class {{name}}Service : I{{name}}Service
|
|
|
2643
2668
|
const diTemplate = `// Add to DependencyInjection.cs or ServiceCollectionExtensions.cs:
|
|
2644
2669
|
services.AddScoped<I{{name}}Service, {{name}}Service>();
|
|
2645
2670
|
`;
|
|
2646
|
-
const context = {
|
|
2671
|
+
const context = { interfaceNamespace, implNamespace, name, methods };
|
|
2647
2672
|
const interfaceContent = Handlebars.compile(interfaceTemplate)(context);
|
|
2648
2673
|
const implementationContent = Handlebars.compile(implementationTemplate)(context);
|
|
2649
2674
|
const diContent = Handlebars.compile(diTemplate)(context);
|
|
2650
2675
|
const projectRoot = config.smartstack.projectPath;
|
|
2651
|
-
const
|
|
2652
|
-
const
|
|
2653
|
-
const
|
|
2654
|
-
const
|
|
2676
|
+
const appPath = structure.application || projectRoot;
|
|
2677
|
+
const infraPath = structure.infrastructure || path8.join(projectRoot, "Infrastructure");
|
|
2678
|
+
const interfacesDir = path8.join(appPath, "Common", "Interfaces");
|
|
2679
|
+
const implDir = hierarchy.infraPath ? path8.join(infraPath, "Services", hierarchy.infraPath) : path8.join(infraPath, "Services");
|
|
2680
|
+
const interfacePath = path8.join(interfacesDir, `I${name}Service.cs`);
|
|
2681
|
+
const implementationPath = path8.join(implDir, `${name}Service.cs`);
|
|
2655
2682
|
validatePathSecurity(interfacePath, projectRoot);
|
|
2656
2683
|
validatePathSecurity(implementationPath, projectRoot);
|
|
2657
2684
|
if (!dryRun) {
|
|
2658
|
-
await ensureDirectory(
|
|
2685
|
+
await ensureDirectory(interfacesDir);
|
|
2686
|
+
await ensureDirectory(implDir);
|
|
2659
2687
|
await writeText(interfacePath, interfaceContent);
|
|
2660
2688
|
await writeText(implementationPath, implementationContent);
|
|
2661
2689
|
}
|
|
@@ -2665,7 +2693,8 @@ services.AddScoped<I{{name}}Service, {{name}}Service>();
|
|
|
2665
2693
|
result.instructions.push(diContent);
|
|
2666
2694
|
}
|
|
2667
2695
|
async function scaffoldEntity(name, options, structure, config, result, dryRun = false) {
|
|
2668
|
-
const
|
|
2696
|
+
const hierarchy = resolveHierarchy(options?.navRoute);
|
|
2697
|
+
const namespace = options?.namespace || (hierarchy.domainPath ? `${config.conventions.namespaces.domain}.${hierarchy.domainPath.replace(/[\\/]/g, ".")}` : config.conventions.namespaces.domain);
|
|
2669
2698
|
const baseEntity = options?.baseEntity;
|
|
2670
2699
|
const isSystemEntity = options?.isSystemEntity || false;
|
|
2671
2700
|
const tablePrefix = options?.tablePrefix || "ref_";
|
|
@@ -2895,15 +2924,17 @@ public class {{name}}Configuration : IEntityTypeConfiguration<{{name}}>
|
|
|
2895
2924
|
const entityContent = Handlebars.compile(entityTemplate)(context);
|
|
2896
2925
|
const configContent = Handlebars.compile(configTemplate)(context);
|
|
2897
2926
|
const projectRoot = config.smartstack.projectPath;
|
|
2898
|
-
const
|
|
2899
|
-
const
|
|
2900
|
-
const
|
|
2901
|
-
const
|
|
2927
|
+
const domainBase = structure.domain || path8.join(projectRoot, "Domain");
|
|
2928
|
+
const infraBase = structure.infrastructure || path8.join(projectRoot, "Infrastructure");
|
|
2929
|
+
const entityDir = hierarchy.domainPath ? path8.join(domainBase, hierarchy.domainPath) : domainBase;
|
|
2930
|
+
const configDir = hierarchy.infraPath ? path8.join(infraBase, "Persistence", "Configurations", hierarchy.infraPath) : path8.join(infraBase, "Persistence", "Configurations");
|
|
2931
|
+
const entityFilePath = path8.join(entityDir, `${name}.cs`);
|
|
2932
|
+
const configFilePath = path8.join(configDir, `${name}Configuration.cs`);
|
|
2902
2933
|
validatePathSecurity(entityFilePath, projectRoot);
|
|
2903
2934
|
validatePathSecurity(configFilePath, projectRoot);
|
|
2904
2935
|
if (!dryRun) {
|
|
2905
|
-
await ensureDirectory(
|
|
2906
|
-
await ensureDirectory(
|
|
2936
|
+
await ensureDirectory(entityDir);
|
|
2937
|
+
await ensureDirectory(configDir);
|
|
2907
2938
|
await writeText(entityFilePath, entityContent);
|
|
2908
2939
|
await writeText(configFilePath, configContent);
|
|
2909
2940
|
}
|
|
@@ -3220,7 +3251,8 @@ GO
|
|
|
3220
3251
|
result.instructions.push("- Group memberships (user belongs to parent groups)");
|
|
3221
3252
|
}
|
|
3222
3253
|
async function scaffoldController(name, options, structure, config, result, dryRun = false) {
|
|
3223
|
-
const
|
|
3254
|
+
const hierarchy = resolveHierarchy(options?.navRoute);
|
|
3255
|
+
const namespace = options?.namespace || (hierarchy.controllerArea ? `${config.conventions.namespaces.api}.Controllers.${hierarchy.controllerArea}` : `${config.conventions.namespaces.api}.Controllers`);
|
|
3224
3256
|
const navRoute = options?.navRoute;
|
|
3225
3257
|
const navRouteSuffix = options?.navRouteSuffix;
|
|
3226
3258
|
const routeAttribute = navRoute ? navRouteSuffix ? `[NavRoute("${navRoute}", Suffix = "${navRouteSuffix}")]` : `[NavRoute("${navRoute}")]` : `[Route("api/[controller]")]`;
|
|
@@ -3316,11 +3348,11 @@ public record Update{{name}}Request();
|
|
|
3316
3348
|
const controllerContent = Handlebars.compile(controllerTemplate)(context);
|
|
3317
3349
|
const projectRoot = config.smartstack.projectPath;
|
|
3318
3350
|
const apiPath = structure.api || path8.join(projectRoot, "Api");
|
|
3319
|
-
const
|
|
3320
|
-
const controllerFilePath = path8.join(
|
|
3351
|
+
const controllersDir = hierarchy.controllerArea ? path8.join(apiPath, "Controllers", hierarchy.controllerArea) : path8.join(apiPath, "Controllers");
|
|
3352
|
+
const controllerFilePath = path8.join(controllersDir, `${name}Controller.cs`);
|
|
3321
3353
|
validatePathSecurity(controllerFilePath, projectRoot);
|
|
3322
3354
|
if (!dryRun) {
|
|
3323
|
-
await ensureDirectory(
|
|
3355
|
+
await ensureDirectory(controllersDir);
|
|
3324
3356
|
await writeText(controllerFilePath, controllerContent);
|
|
3325
3357
|
}
|
|
3326
3358
|
result.files.push({ path: controllerFilePath, content: controllerContent, type: "created" });
|
|
@@ -3346,6 +3378,7 @@ public record Update{{name}}Request();
|
|
|
3346
3378
|
}
|
|
3347
3379
|
}
|
|
3348
3380
|
async function scaffoldComponent(name, options, structure, config, result, dryRun = false) {
|
|
3381
|
+
const hierarchy = resolveHierarchy(options?.navRoute);
|
|
3349
3382
|
const componentTemplate = `import React, { useState, useEffect } from 'react';
|
|
3350
3383
|
|
|
3351
3384
|
interface {{name}}Props {
|
|
@@ -3498,7 +3531,8 @@ export function use{{name}}(options: Use{{name}}Options = {}) {
|
|
|
3498
3531
|
const hookContent = Handlebars.compile(hookTemplate)(context);
|
|
3499
3532
|
const projectRoot = config.smartstack.projectPath;
|
|
3500
3533
|
const webPath = structure.web || path8.join(projectRoot, "web");
|
|
3501
|
-
const
|
|
3534
|
+
const componentsBase = path8.join(webPath, "src", "components");
|
|
3535
|
+
const componentsPath = options?.outputPath ? options.outputPath : hierarchy.context && hierarchy.module ? path8.join(componentsBase, hierarchy.context.toLowerCase(), hierarchy.module.toLowerCase()) : componentsBase;
|
|
3502
3536
|
const hooksPath = path8.join(webPath, "src", "hooks");
|
|
3503
3537
|
const componentFilePath = path8.join(componentsPath, `${name}.tsx`);
|
|
3504
3538
|
const hookFilePath = path8.join(hooksPath, `use${name}.ts`);
|
|
@@ -3513,8 +3547,9 @@ export function use{{name}}(options: Use{{name}}Options = {}) {
|
|
|
3513
3547
|
result.files.push({ path: componentFilePath, content: componentContent, type: "created" });
|
|
3514
3548
|
result.files.push({ path: hookFilePath, content: hookContent, type: "created" });
|
|
3515
3549
|
result.instructions.push("Import and use the component:");
|
|
3516
|
-
|
|
3517
|
-
result.instructions.push(`import {
|
|
3550
|
+
const componentImportPath = hierarchy.context && hierarchy.module ? `@/components/${hierarchy.context.toLowerCase()}/${hierarchy.module.toLowerCase()}/${name}` : `./components/${name}`;
|
|
3551
|
+
result.instructions.push(`import { ${name} } from '${componentImportPath}';`);
|
|
3552
|
+
result.instructions.push(`import { use${name} } from '@/hooks/use${name}';`);
|
|
3518
3553
|
}
|
|
3519
3554
|
async function scaffoldTest(name, options, structure, config, result, dryRun = false) {
|
|
3520
3555
|
const isSystemEntity = options?.isSystemEntity || false;
|
|
@@ -3642,7 +3677,8 @@ public class {{name}}ServiceTests
|
|
|
3642
3677
|
result.instructions.push("- FluentAssertions");
|
|
3643
3678
|
}
|
|
3644
3679
|
async function scaffoldDtos(name, options, structure, config, result, dryRun = false) {
|
|
3645
|
-
const
|
|
3680
|
+
const hierarchy = resolveHierarchy(options?.navRoute);
|
|
3681
|
+
const namespace = options?.namespace || (hierarchy.domainPath ? `${config.conventions.namespaces.application}.${hierarchy.domainPath.replace(/[\\/]/g, ".")}.DTOs` : `${config.conventions.namespaces.application}.DTOs`);
|
|
3646
3682
|
const isSystemEntity = options?.isSystemEntity || false;
|
|
3647
3683
|
const properties = options?.entityProperties || [
|
|
3648
3684
|
{ name: "Name", type: "string", required: true, maxLength: 200 },
|
|
@@ -3759,7 +3795,7 @@ public record Update{{name}}Dto
|
|
|
3759
3795
|
const createContent = Handlebars.compile(createDtoTemplate)(context);
|
|
3760
3796
|
const updateContent = Handlebars.compile(updateDtoTemplate)(context);
|
|
3761
3797
|
const basePath = structure.application || config.smartstack.projectPath;
|
|
3762
|
-
const dtosPath = path8.join(basePath, "DTOs", name);
|
|
3798
|
+
const dtosPath = hierarchy.domainPath ? path8.join(basePath, hierarchy.domainPath, "DTOs") : path8.join(basePath, "DTOs", name);
|
|
3763
3799
|
const responseFilePath = path8.join(dtosPath, `${name}ResponseDto.cs`);
|
|
3764
3800
|
const createFilePath = path8.join(dtosPath, `Create${name}Dto.cs`);
|
|
3765
3801
|
const updateFilePath = path8.join(dtosPath, `Update${name}Dto.cs`);
|
|
@@ -3778,7 +3814,8 @@ public record Update{{name}}Dto
|
|
|
3778
3814
|
result.instructions.push(`- Update${name}Dto: For PUT requests`);
|
|
3779
3815
|
}
|
|
3780
3816
|
async function scaffoldValidator(name, options, structure, config, result, dryRun = false) {
|
|
3781
|
-
const
|
|
3817
|
+
const hierarchy = resolveHierarchy(options?.navRoute);
|
|
3818
|
+
const namespace = options?.namespace || (hierarchy.domainPath ? `${config.conventions.namespaces.application}.${hierarchy.domainPath.replace(/[\\/]/g, ".")}.Validators` : `${config.conventions.namespaces.application}.Validators`);
|
|
3782
3819
|
const properties = options?.entityProperties || [
|
|
3783
3820
|
{ name: "Name", type: "string", required: true, maxLength: 200 },
|
|
3784
3821
|
{ name: "Description", type: "string?", required: false, maxLength: 500 }
|
|
@@ -3856,7 +3893,7 @@ public class Update{{name}}DtoValidator : AbstractValidator<Update{{name}}Dto>
|
|
|
3856
3893
|
const createValidatorContent = Handlebars.compile(createValidatorTemplate)(context);
|
|
3857
3894
|
const updateValidatorContent = Handlebars.compile(updateValidatorTemplate)(context);
|
|
3858
3895
|
const basePath = structure.application || config.smartstack.projectPath;
|
|
3859
|
-
const validatorsPath = path8.join(basePath, "Validators");
|
|
3896
|
+
const validatorsPath = hierarchy.domainPath ? path8.join(basePath, hierarchy.domainPath, "Validators") : path8.join(basePath, "Validators");
|
|
3860
3897
|
const createValidatorFilePath = path8.join(validatorsPath, `Create${name}DtoValidator.cs`);
|
|
3861
3898
|
const updateValidatorFilePath = path8.join(validatorsPath, `Update${name}DtoValidator.cs`);
|
|
3862
3899
|
if (!dryRun) {
|
|
@@ -3872,6 +3909,7 @@ public class Update{{name}}DtoValidator : AbstractValidator<Update{{name}}Dto>
|
|
|
3872
3909
|
result.instructions.push("Required package: FluentValidation.DependencyInjectionExtensions");
|
|
3873
3910
|
}
|
|
3874
3911
|
async function scaffoldRepository(name, options, structure, config, result, dryRun = false) {
|
|
3912
|
+
const hierarchy = resolveHierarchy(options?.navRoute);
|
|
3875
3913
|
const isSystemEntity = options?.isSystemEntity || false;
|
|
3876
3914
|
const schema = options?.schema || config.conventions.schemas.platform;
|
|
3877
3915
|
const dbContextName = schema === "extensions" ? "ExtensionsDbContext" : "CoreDbContext";
|
|
@@ -3995,11 +4033,13 @@ public class {{name}}Repository : I{{name}}Repository
|
|
|
3995
4033
|
const implementationContent = Handlebars.compile(implementationTemplate)(context);
|
|
3996
4034
|
const appPath = structure.application || config.smartstack.projectPath;
|
|
3997
4035
|
const infraPath = structure.infrastructure || path8.join(config.smartstack.projectPath, "Infrastructure");
|
|
3998
|
-
const
|
|
3999
|
-
const
|
|
4036
|
+
const appRepoDir = hierarchy.infraPath ? path8.join(appPath, "Repositories", hierarchy.infraPath) : path8.join(appPath, "Repositories");
|
|
4037
|
+
const infraRepoDir = hierarchy.infraPath ? path8.join(infraPath, "Repositories", hierarchy.infraPath) : path8.join(infraPath, "Repositories");
|
|
4038
|
+
const interfaceFilePath = path8.join(appRepoDir, `I${name}Repository.cs`);
|
|
4039
|
+
const implementationFilePath = path8.join(infraRepoDir, `${name}Repository.cs`);
|
|
4000
4040
|
if (!dryRun) {
|
|
4001
|
-
await ensureDirectory(
|
|
4002
|
-
await ensureDirectory(
|
|
4041
|
+
await ensureDirectory(appRepoDir);
|
|
4042
|
+
await ensureDirectory(infraRepoDir);
|
|
4003
4043
|
await writeText(interfaceFilePath, interfaceContent);
|
|
4004
4044
|
await writeText(implementationFilePath, implementationContent);
|
|
4005
4045
|
}
|