diff --git a/MycroForge.CLI/CodeGen/CrudRouterGenerator.cs b/MycroForge.CLI/CodeGen/CrudRouterGenerator.cs index 9108c6b..8eb9cd3 100644 --- a/MycroForge.CLI/CodeGen/CrudRouterGenerator.cs +++ b/MycroForge.CLI/CodeGen/CrudRouterGenerator.cs @@ -20,7 +20,7 @@ public class CrudRouterGenerator "", "@router.get(\"/\")", "async def list(", - "\tservice: Annotated[%service_class_name%, Depends(%service_class_name%)]", + "\tservice: Annotated[%service_class_name%, Depends()]", "):", "\ttry:", "\t\tresult = await service.list()", @@ -32,7 +32,7 @@ public class CrudRouterGenerator "@router.get(\"/{id}\")", "async def get_by_id(", "\tid: int,", - "\tservice: Annotated[%service_class_name%, Depends(%service_class_name%)]", + "\tservice: Annotated[%service_class_name%, Depends()]", "):", "\ttry:", "\t\tresult = await service.get_by_id(id)", @@ -44,7 +44,7 @@ public class CrudRouterGenerator "@router.post(\"/\")", "async def create(", "\trequest: Create%entity_class_name%Request,", - "\tservice: Annotated[%service_class_name%, Depends(%service_class_name%)]", + "\tservice: Annotated[%service_class_name%, Depends()]", "):", "\ttry:", "\t\tawait service.create(request.model_dump())", @@ -57,7 +57,7 @@ public class CrudRouterGenerator "async def update(", "\tid: int,", "\trequest: Update%entity_class_name%Request,", - "\tservice: Annotated[%service_class_name%, Depends(%service_class_name%)]", + "\tservice: Annotated[%service_class_name%, Depends()]", "):", "\ttry:", "\t\tupdated = await service.update(id, request.model_dump(exclude_unset=True))", @@ -69,7 +69,7 @@ public class CrudRouterGenerator "@router.delete(\"/{id}\")", "async def delete(", "\tid: int,", - "\tservice: Annotated[%service_class_name%, Depends(%service_class_name%)]", + "\tservice: Annotated[%service_class_name%, Depends()]", "):", "\ttry:", "\t\tdeleted = await service.delete(id)", diff --git a/MycroForge.CLI/CodeGen/EntityLinker.cs b/MycroForge.CLI/CodeGen/EntityLinker.cs index 8c7feb0..8221ad5 100644 --- a/MycroForge.CLI/CodeGen/EntityLinker.cs +++ b/MycroForge.CLI/CodeGen/EntityLinker.cs @@ -1,4 +1,5 @@ using Humanizer; +using MycroForge.CLI.Commands; using MycroForge.Core; namespace MycroForge.CLI.CodeGen; @@ -143,16 +144,14 @@ public partial class EntityLinker private async Task LoadEntity(string name) { + var fqn = new FullyQualifiedName(name); var path = $"{Features.Db.FeatureName}/entities"; - if (name.Split(':').Select(s => s.Trim()).ToArray() is { Length: 2 } fullName) - { - path = Path.Combine(path, fullName[0]); - name = fullName[1]; - } + if (fqn.HasPath) + path = Path.Combine(path, fqn.Path); - path = Path.Combine(path, $"{name.Underscore().ToLower()}.py"); - var entity = new EntityModel(name, path, await _context.ReadFile(path)); + path = Path.Combine(path, $"{fqn.SnakeCasedName}.py"); + var entity = new EntityModel(fqn.PascalizedName, path, await _context.ReadFile(path)); entity.Initialize(); return entity; } diff --git a/MycroForge.CLI/Commands/FullyQualifiedName.cs b/MycroForge.CLI/Commands/FullyQualifiedName.cs new file mode 100644 index 0000000..09bcf96 --- /dev/null +++ b/MycroForge.CLI/Commands/FullyQualifiedName.cs @@ -0,0 +1,28 @@ +using Humanizer; + +namespace MycroForge.CLI.Commands; + +public class FullyQualifiedName +{ + public string Path { get; } + public string PascalizedName { get; } + public string SnakeCasedName { get; } + + public bool HasPath => Path.Length > 0; + + + public FullyQualifiedName(string name) + { + var path = string.Empty; + + if (name.Split(':').Select(s => s.Trim()).ToArray() is { Length: 2 } fullName) + { + path = fullName[0]; + name = fullName[1]; + } + + Path = path; + PascalizedName = name.Pascalize(); + SnakeCasedName = name.Underscore().ToLower(); + } +} diff --git a/MycroForge.CLI/Commands/MycroForge.Api.Generate.Crud.cs b/MycroForge.CLI/Commands/MycroForge.Api.Generate.Crud.cs index c9a1275..f57b1d0 100644 --- a/MycroForge.CLI/Commands/MycroForge.Api.Generate.Crud.cs +++ b/MycroForge.CLI/Commands/MycroForge.Api.Generate.Crud.cs @@ -28,17 +28,12 @@ public partial class MycroForge private async Task ExecuteAsync(string entity) { - var path = string.Empty; - if (entity.Split(':').Select(s => s.Trim()).ToArray() is { Length: 2 } fullName) - { - path = fullName[0]; - entity = fullName[1]; - } + var fqn = new FullyQualifiedName(entity); - await new CrudServiceGenerator(_context).Generate(path, entity); - await new RequestClassGenerator(_context).Generate(path, entity, RequestClassGenerator.Type.Create); - await new RequestClassGenerator(_context).Generate(path, entity, RequestClassGenerator.Type.Update); - await new CrudRouterGenerator(_context).Generate(path, entity); + await new CrudServiceGenerator(_context).Generate(fqn.Path, fqn.PascalizedName); + await new RequestClassGenerator(_context).Generate(fqn.Path, fqn.PascalizedName, RequestClassGenerator.Type.Create); + await new RequestClassGenerator(_context).Generate(fqn.Path, fqn.PascalizedName, RequestClassGenerator.Type.Update); + await new CrudRouterGenerator(_context).Generate(fqn.Path, fqn.PascalizedName); } } } diff --git a/MycroForge.CLI/Commands/MycroForge.Api.Generate.Router.cs b/MycroForge.CLI/Commands/MycroForge.Api.Generate.Router.cs index 7a20e64..d19e4e8 100644 --- a/MycroForge.CLI/Commands/MycroForge.Api.Generate.Router.cs +++ b/MycroForge.CLI/Commands/MycroForge.Api.Generate.Router.cs @@ -1,5 +1,6 @@ using System.CommandLine; using Humanizer; +using MycroForge.CLI.CodeGen; using MycroForge.Core.Contract; using MycroForge.CLI.Extensions; using MycroForge.Core; @@ -42,30 +43,31 @@ public partial class MycroForge private async Task ExecuteAsync(string name) { + var fqn = new FullyQualifiedName(name); var folderPath = $"{Features.Api.FeatureName}/routers"; _context.AssertDirectoryExists(folderPath); - if (name.FullyQualifiedName() is { Length: 2 } fullName) - { - folderPath = Path.Combine(folderPath, fullName[0]); - name = fullName[1]; - } - - var moduleImportPath = folderPath.Replace('\\', '.').Replace('/', '.'); - var moduleName = name.Underscore().ToLower(); - var fileName = $"{moduleName}.py"; + if (fqn.HasPath) + folderPath = Path.Combine(folderPath, fqn.Path); + + var fileName = $"{fqn.SnakeCasedName}.py"; var filePath = Path.Combine(folderPath, fileName); await _context.CreateFile(filePath, Template); + + var moduleImportPath = folderPath + .Replace('\\', '.') + .Replace('/', '.'); var main = await _context.ReadFile("main.py"); - - main += string.Join('\n', - $"\n\nfrom {moduleImportPath} import {moduleName}", - $"app.include_router(prefix=\"/{name.Kebaberize()}\", router={moduleName}.router)" - ); - + + main = new MainModifier(main) + .Initialize() + .Import(from: moduleImportPath, import: fqn.SnakeCasedName) + .IncludeRouter(prefix: name.Kebaberize(), router: fqn.SnakeCasedName) + .Rewrite(); + await _context.WriteFile("main.py", main); } } diff --git a/MycroForge.CLI/Commands/MycroForge.Db.Generate.Entity.cs b/MycroForge.CLI/Commands/MycroForge.Db.Generate.Entity.cs index e0ab45b..27d40a4 100644 --- a/MycroForge.CLI/Commands/MycroForge.Db.Generate.Entity.cs +++ b/MycroForge.CLI/Commands/MycroForge.Db.Generate.Entity.cs @@ -69,28 +69,25 @@ public partial class MycroForge private async Task ExecuteAsync(string name, IEnumerable columns) { + var fqn = new FullyQualifiedName(name); var folderPath = $"{Features.Db.FeatureName}/entities"; _context.AssertDirectoryExists(Features.Db.FeatureName); - if (name.FullyQualifiedName() is { Length: 2 } fullName) - { - folderPath = Path.Combine(folderPath, fullName[0]); - name = fullName[1]; - } + if (fqn.HasPath) + folderPath = Path.Combine(folderPath, fqn.Path); var _columns = GetColumnDefinitions(columns.ToArray()); - var className = name.Underscore().Pascalize(); var typeImports = string.Join(", ", _columns.Select(c => c.OrmType.Split('(').First()).Distinct()); var columnDefinitions = string.Join("\n\t", _columns.Select(ColumnToString)); var code = string.Join('\n', Template); code = code.Replace("%type_imports%", typeImports); - code = code.Replace("%class_name%", className); - code = code.Replace("%table_name%", name.Underscore().ToLower().Pluralize()); + code = code.Replace("%class_name%", fqn.PascalizedName); + code = code.Replace("%table_name%", fqn.SnakeCasedName.Pluralize()); code = code.Replace("%column_definitions%", columnDefinitions); - var fileName = $"{name.Underscore().ToLower()}.py"; + var fileName = $"{fqn.SnakeCasedName}.py"; var filePath = Path.Combine(folderPath, fileName); await _context.CreateFile(filePath, code); @@ -104,11 +101,11 @@ public partial class MycroForge .ToLower(); var env = await _context.ReadFile($"{Features.Db.FeatureName}/env.py"); - env = new DbEnvModifier(env, importPath, className).Rewrite(); + env = new DbEnvModifier(env, importPath, fqn.PascalizedName).Rewrite(); await _context.WriteFile($"{Features.Db.FeatureName}/env.py", env); var main = await _context.ReadFile("main.py"); - main = new MainModifier(main).Initialize().Import(importPath, className).Rewrite(); + main = new MainModifier(main).Initialize().Import(importPath, fqn.PascalizedName).Rewrite(); await _context.WriteFile("main.py", main); } diff --git a/MycroForge.CLI/Commands/MycroForge.Generate.Service.cs b/MycroForge.CLI/Commands/MycroForge.Generate.Service.cs index 605bba2..a5e7bee 100644 --- a/MycroForge.CLI/Commands/MycroForge.Generate.Service.cs +++ b/MycroForge.CLI/Commands/MycroForge.Generate.Service.cs @@ -57,18 +57,16 @@ public partial class MycroForge private async Task ExecuteAsync(string name, bool withSession) { + var fqn = new FullyQualifiedName(name); var folderPath = string.Empty; - if (name.FullyQualifiedName() is { Length: 2} fullName) - { - folderPath = Path.Combine(folderPath, fullName[0]); - name = fullName[1]; - } + if (fqn.HasPath) + folderPath = Path.Combine(folderPath, fqn.Path); - var filePath = Path.Combine(folderPath, $"{name.Underscore().ToLower()}.py"); - var className = Path.GetFileName(name).Pascalize(); - var code = string.Join('\n', withSession ? WithSessionTemplate : DefaultTemplate) - .Replace("%class_name%", className); + var filePath = Path.Combine(folderPath, $"{fqn.SnakeCasedName}.py"); + var template = withSession ? WithSessionTemplate : DefaultTemplate; + var code = string.Join('\n', template) + .Replace("%class_name%", fqn.PascalizedName); await _context.CreateFile(filePath, code); } diff --git a/MycroForge.CLI/Extensions/StringExtensions.cs b/MycroForge.CLI/Extensions/StringExtensions.cs index 3f924f5..a75c322 100644 --- a/MycroForge.CLI/Extensions/StringExtensions.cs +++ b/MycroForge.CLI/Extensions/StringExtensions.cs @@ -2,11 +2,6 @@ public static class StringExtensions { - public static string[] FullyQualifiedName(this string name) - { - return name.Split(':').Select(s => s.Trim()).ToArray(); - } - public static string DeduplicateDots(this string path) { while (path.Contains("..")) diff --git a/MycroForge.CLI/Features/Api.cs b/MycroForge.CLI/Features/Api.cs index 1c10342..a13036a 100644 --- a/MycroForge.CLI/Features/Api.cs +++ b/MycroForge.CLI/Features/Api.cs @@ -23,11 +23,10 @@ public sealed partial class Api : IFeature private static readonly string[] MainTemplate = [ "from fastapi import FastAPI", - "", + $"from {FeatureName}.routers import hello", "", "app = FastAPI()", "", - $"from {FeatureName}.routers import hello", "app.include_router(prefix=\"/hello\", router=hello.router)" ];