diff --git a/TopModel.Generator.Csharp/CSharpApiClientGenerator.cs b/TopModel.Generator.Csharp/CSharpApiClientGenerator.cs index e2a4736b..8ac8781e 100644 --- a/TopModel.Generator.Csharp/CSharpApiClientGenerator.cs +++ b/TopModel.Generator.Csharp/CSharpApiClientGenerator.cs @@ -29,6 +29,11 @@ protected override string GetFilePath(ModelFile file, string tag) return Path.Combine(Config.GetApiPath(file, tag), "generated", $"{file.Options.Endpoints.FileName.ToPascalCase()}Client.cs"); } + protected virtual string GetNamespace(Class classe, string tag) + { + return Config.GetNamespace(classe, classe.Tags.Contains(tag) ? tag : classe.Tags.Intersect(Config.Tags).FirstOrDefault() ?? tag); + } + protected override void HandleFile(string filePath, string fileName, string tag, IList endpoints) { var className = $"{fileName.ToPascalCase()}Client"; @@ -296,12 +301,7 @@ protected override void HandleFile(string filePath, string fileName, string tag, fw.WriteLine("}"); } - private string GetNamespace(Class classe, string tag) - { - return Config.GetNamespace(classe, classe.Tags.Contains(tag) ? tag : classe.Tags.Intersect(Config.Tags).FirstOrDefault() ?? tag); - } - - private void HandleFilePartial(string filePath, string className, string ns) + protected virtual void HandleFilePartial(string filePath, string className, string ns) { if (File.Exists(filePath)) { diff --git a/TopModel.Generator.Csharp/CSharpApiServerGenerator.cs b/TopModel.Generator.Csharp/CSharpApiServerGenerator.cs index 70660f7d..cb1971dd 100644 --- a/TopModel.Generator.Csharp/CSharpApiServerGenerator.cs +++ b/TopModel.Generator.Csharp/CSharpApiServerGenerator.cs @@ -33,6 +33,64 @@ protected override string GetFilePath(ModelFile file, string tag) return Path.Combine(Config.GetApiPath(file, tag, withControllers: true), $"{file.Options.Endpoints.FileName.ToPascalCase()}Controller.cs"); } + protected virtual string GetParam(IProperty param) + { + var sb = new StringBuilder(); + + var type = Config.GetType(param, nonNullable: param.IsJsonBodyParam() || param.IsRouteParam() || param.IsQueryParam() && !param.Endpoint.IsMultipart && Config.GetValue(param, Classes) != "null"); + + if (param.Endpoint.IsMultipart && !param.IsQueryParam() && !param.IsRouteParam() && type != "IFormFile") + { + sb.Append("[FromForm] "); + } + else if (param.IsJsonBodyParam()) + { + sb.Append("[FromBody] "); + } + else if (type.EndsWith("[]")) + { + sb.Append("[FromQuery] "); + } + + sb.Append($@"{type} {param.GetParamName().Verbatim()}"); + + if (param.IsQueryParam() && !param.Endpoint.IsMultipart) + { + sb.Append($" = {Config.GetValue(param, Classes)}"); + } + + return sb.ToString(); + } + + protected virtual string GetRoute(Endpoint endpoint) + { + var split = endpoint.FullRoute.Split("/"); + + for (var i = 0; i < split.Length; i++) + { + if (split[i].StartsWith('{')) + { + var routeParamName = split[i][1..^1]; + var param = endpoint.Params.Single(param => param.GetParamName() == routeParamName); + + var paramType = Config.GetType(param) switch + { + "int" => "int", + "int?" => "int", + "Guid" => "guid", + "Guid?" => "guid", + _ => null + }; + if (paramType != null) + { + split[i] = $"{{{routeParamName}:{paramType}}}"; + } + } + } + + return string.Join("/", split); + } + protected override void HandleFile(string filePath, string fileName, string tag, IList endpoints) { var className = $"{fileName.ToPascalCase()}Controller"; @@ -125,62 +183,4 @@ public class {className} : Controller using var fw = new FileWriter(filePath, _logger, true) { HeaderMessage = "ATTENTION, CE FICHIER EST PARTIELLEMENT GENERE AUTOMATIQUEMENT !" }; fw.Write(syntaxTree.GetRoot().ReplaceNode(existingController, controller).ToString()); } - - private string GetParam(IProperty param) - { - var sb = new StringBuilder(); - - var type = Config.GetType(param, nonNullable: param.IsJsonBodyParam() || param.IsRouteParam() || param.IsQueryParam() && !param.Endpoint.IsMultipart && Config.GetValue(param, Classes) != "null"); - - if (param.Endpoint.IsMultipart && !param.IsQueryParam() && !param.IsRouteParam() && type != "IFormFile") - { - sb.Append("[FromForm] "); - } - else if (param.IsJsonBodyParam()) - { - sb.Append("[FromBody] "); - } - else if (type.EndsWith("[]")) - { - sb.Append("[FromQuery] "); - } - - sb.Append($@"{type} {param.GetParamName().Verbatim()}"); - - if (param.IsQueryParam() && !param.Endpoint.IsMultipart) - { - sb.Append($" = {Config.GetValue(param, Classes)}"); - } - - return sb.ToString(); - } - - private string GetRoute(Endpoint endpoint) - { - var split = endpoint.FullRoute.Split("/"); - - for (var i = 0; i < split.Length; i++) - { - if (split[i].StartsWith('{')) - { - var routeParamName = split[i][1..^1]; - var param = endpoint.Params.Single(param => param.GetParamName() == routeParamName); - - var paramType = Config.GetType(param) switch - { - "int" => "int", - "int?" => "int", - "Guid" => "guid", - "Guid?" => "guid", - _ => null - }; - if (paramType != null) - { - split[i] = $"{{{routeParamName}:{paramType}}}"; - } - } - } - - return string.Join("/", split); - } } \ No newline at end of file diff --git a/TopModel.Generator.Csharp/CSharpClassGenerator.cs b/TopModel.Generator.Csharp/CSharpClassGenerator.cs index 422c4081..83897a15 100644 --- a/TopModel.Generator.Csharp/CSharpClassGenerator.cs +++ b/TopModel.Generator.Csharp/CSharpClassGenerator.cs @@ -11,15 +11,6 @@ public class CSharpClassGenerator : ClassGeneratorBase { private readonly ILogger _logger; - private readonly Dictionary _newableTypes = new() - { - ["IEnumerable"] = "List", - ["ICollection"] = "List", - ["IList"] = "List", - ["List"] = "List", - ["HashSet"] = "HashSet" - }; - public CSharpClassGenerator(ILogger logger) : base(logger) { @@ -28,92 +19,14 @@ public CSharpClassGenerator(ILogger logger) public override string Name => "CSharpClassGen"; - protected override string GetFileName(Class classe, string tag) - { - return Config.GetClassFileName(classe, tag); - } - - protected override void HandleClass(string fileName, Class classe, string tag) - { - using var w = new CSharpWriter(fileName, _logger); - - GenerateUsings(w, classe, tag); - w.WriteNamespace(Config.GetNamespace(classe, tag)); - w.WriteSummary(classe.Comment); - GenerateClassDeclaration(w, classe, tag); - } - - /// - /// Génère le type énuméré présentant les colonnes persistentes. - /// - /// Writer. - /// La classe générée. - private static void GenerateEnumCols(CSharpWriter w, Class item) + protected virtual Dictionary NewableTypes { get; } = new() { - w.WriteLine(1, "#region Meta données"); - w.WriteLine(); - w.WriteSummary(1, "Type énuméré présentant les noms des colonnes en base."); - - if (item.Extends == null) - { - w.WriteLine(1, "public enum Cols"); - } - else - { - w.WriteLine(1, "public new enum Cols"); - } - - w.WriteLine(1, "{"); - - foreach (var property in item.Properties) - { - w.WriteSummary(2, "Nom de la colonne en base associée à la propriété " + property.NamePascal + "."); - w.WriteLine(2, $"{property.SqlName},"); - if (item.Properties.IndexOf(property) != item.Properties.Count - 1) - { - w.WriteLine(); - } - } - - w.WriteLine(1, "}"); - w.WriteLine(); - w.WriteLine(1, "#endregion"); - w.WriteLine(); - } - - /// - /// Génère les flags d'une liste de référence statique. - /// - /// Writer. - /// La classe générée. - private static void GenerateFlags(CSharpWriter w, Class item) - { - if (item.FlagProperty != null && item.Values.Any()) - { - w.WriteLine(1, "#region Flags"); - w.WriteLine(); - w.WriteSummary(1, "Flags"); - w.WriteLine(1, "public enum Flags"); - w.WriteLine(1, "{"); - - var flagValues = item.Values.Where(refValue => refValue.Value.ContainsKey(item.FlagProperty) && int.TryParse(refValue.Value[item.FlagProperty], out var _)).ToList(); - foreach (var refValue in flagValues) - { - var flag = int.Parse(refValue.Value[item.FlagProperty]); - w.WriteSummary(2, refValue.GetLabel(item)); - w.WriteLine(2, $"{refValue.Name} = 0b{Convert.ToString(flag, 2)},"); - if (flagValues.IndexOf(refValue) != flagValues.Count - 1) - { - w.WriteLine(); - } - } - - w.WriteLine(1, "}"); - w.WriteLine(); - w.WriteLine(1, "#endregion"); - w.WriteLine(); - } - } + ["IEnumerable"] = "List", + ["ICollection"] = "List", + ["IList"] = "List", + ["List"] = "List", + ["HashSet"] = "HashSet" + }; /// /// Génération de la déclaration de la classe. @@ -121,7 +34,7 @@ private static void GenerateFlags(CSharpWriter w, Class item) /// Writer /// Classe à générer. /// Tag. - private void GenerateClassDeclaration(CSharpWriter w, Class item, string tag) + protected virtual void GenerateClassDeclaration(CSharpWriter w, Class item, string tag) { if (!item.Abstract) { @@ -208,7 +121,7 @@ private void GenerateClassDeclaration(CSharpWriter w, Class item, string tag) /// /// Writer. /// La classe générée. - private void GenerateConstProperties(CSharpWriter w, Class item) + protected virtual void GenerateConstProperties(CSharpWriter w, Class item) { var consts = new List<(IProperty Prop, string Name, string Code, string Label)>(); @@ -256,7 +169,7 @@ private void GenerateConstProperties(CSharpWriter w, Class item) } } - private void GenerateCreateMethod(CSharpWriter w, Class item) + protected virtual void GenerateCreateMethod(CSharpWriter w, Class item) { var writeProperties = item.Properties.Where(p => !p.Readonly); @@ -274,12 +187,50 @@ private void GenerateCreateMethod(CSharpWriter w, Class item) } } + /// + /// Génère le type énuméré présentant les colonnes persistentes. + /// + /// Writer. + /// La classe générée. + protected virtual void GenerateEnumCols(CSharpWriter w, Class item) + { + w.WriteLine(1, "#region Meta données"); + w.WriteLine(); + w.WriteSummary(1, "Type énuméré présentant les noms des colonnes en base."); + + if (item.Extends == null) + { + w.WriteLine(1, "public enum Cols"); + } + else + { + w.WriteLine(1, "public new enum Cols"); + } + + w.WriteLine(1, "{"); + + foreach (var property in item.Properties) + { + w.WriteSummary(2, "Nom de la colonne en base associée à la propriété " + property.NamePascal + "."); + w.WriteLine(2, $"{property.SqlName},"); + if (item.Properties.IndexOf(property) != item.Properties.Count - 1) + { + w.WriteLine(); + } + } + + w.WriteLine(1, "}"); + w.WriteLine(); + w.WriteLine(1, "#endregion"); + w.WriteLine(); + } + /// /// Génère l'enum pour les valeurs statiques de références. /// /// Writer. /// La classe générée. - private void GenerateEnumValues(CSharpWriter w, Class item) + protected virtual void GenerateEnumValues(CSharpWriter w, Class item) { bool WriteEnum(IProperty prop) { @@ -331,13 +282,47 @@ bool WriteEnum(IProperty prop) } } + /// + /// Génère les flags d'une liste de référence statique. + /// + /// Writer. + /// La classe générée. + protected virtual void GenerateFlags(CSharpWriter w, Class item) + { + if (item.FlagProperty != null && item.Values.Any()) + { + w.WriteLine(1, "#region Flags"); + w.WriteLine(); + w.WriteSummary(1, "Flags"); + w.WriteLine(1, "public enum Flags"); + w.WriteLine(1, "{"); + + var flagValues = item.Values.Where(refValue => refValue.Value.ContainsKey(item.FlagProperty) && int.TryParse(refValue.Value[item.FlagProperty], out var _)).ToList(); + foreach (var refValue in flagValues) + { + var flag = int.Parse(refValue.Value[item.FlagProperty]); + w.WriteSummary(2, refValue.GetLabel(item)); + w.WriteLine(2, $"{refValue.Name} = 0b{Convert.ToString(flag, 2)},"); + if (flagValues.IndexOf(refValue) != flagValues.Count - 1) + { + w.WriteLine(); + } + } + + w.WriteLine(1, "}"); + w.WriteLine(); + w.WriteLine(1, "#endregion"); + w.WriteLine(); + } + } + /// /// Génère les propriétés. /// /// Writer. /// La classe générée. /// Tag. - private void GenerateProperties(CSharpWriter w, Class item, string tag) + protected virtual void GenerateProperties(CSharpWriter w, Class item, string tag) { var sameColumnSet = new HashSet(item.Properties .GroupBy(g => g.SqlName).Where(g => g.Count() > 1).Select(g => g.Key)); @@ -360,7 +345,7 @@ private void GenerateProperties(CSharpWriter w, Class item, string tag) /// La propriété générée. /// Sets des propriétés avec le même nom de colonne, pour ne pas les gérerer (genre alias). /// Tag. - private void GenerateProperty(CSharpWriter w, IProperty property, HashSet sameColumnSet, string tag) + protected virtual void GenerateProperty(CSharpWriter w, IProperty property, HashSet sameColumnSet, string tag) { w.WriteSummary(1, property.Comment); @@ -466,7 +451,7 @@ private void GenerateProperty(CSharpWriter w, IProperty property, HashSetWriter. /// Classe concernée. /// Tag. - private void GenerateUsings(CSharpWriter w, Class item, string tag) + protected virtual void GenerateUsings(CSharpWriter w, Class item, string tag) { var usings = new List(); @@ -548,12 +533,17 @@ private void GenerateUsings(CSharpWriter w, Class item, string tag) } } - private string GetNamespace(Class classe, string tag) + protected override string GetFileName(Class classe, string tag) + { + return Config.GetClassFileName(classe, tag); + } + + protected virtual string GetNamespace(Class classe, string tag) { return Config.GetNamespace(classe, classe.Tags.Contains(tag) ? tag : classe.Tags.Intersect(Config.Tags).FirstOrDefault() ?? tag); } - private string? GetNewableType(CompositionProperty property) + protected virtual string? GetNewableType(CompositionProperty property) { var type = Config.GetType(property, nonNullable: true); var genericType = type.Split('<').First(); @@ -563,11 +553,21 @@ private string GetNamespace(Class classe, string tag) return type; } - if (_newableTypes.TryGetValue(genericType, out var newableType)) + if (NewableTypes.TryGetValue(genericType, out var newableType)) { return type.Replace(genericType, newableType); } return null; } + + protected override void HandleClass(string fileName, Class classe, string tag) + { + using var w = new CSharpWriter(fileName, _logger); + + GenerateUsings(w, classe, tag); + w.WriteNamespace(Config.GetNamespace(classe, tag)); + w.WriteSummary(classe.Comment); + GenerateClassDeclaration(w, classe, tag); + } } \ No newline at end of file diff --git a/TopModel.Generator.Csharp/CSharpWriter.cs b/TopModel.Generator.Csharp/CSharpWriter.cs index 36739d6b..b252e487 100644 --- a/TopModel.Generator.Csharp/CSharpWriter.cs +++ b/TopModel.Generator.Csharp/CSharpWriter.cs @@ -48,7 +48,7 @@ public void Write(string text) /// /// Niveau d'indentation. /// Valeur à écrire dans le flux. - public void Write(int indentationLevel, string value) + public virtual void Write(int indentationLevel, string value) { var indentValue = GetIdentValue(indentationLevel); value = value.Replace("\r\n", "\r\n" + indentValue); @@ -71,7 +71,7 @@ public void WriteAttribute(string attributeName, params string[] attributeParams /// Indentation. /// Nom de l'attribut. /// Paramètres. - public void WriteAttribute(int indentLevel, string attributeName, params string[] attributeParams) + public virtual void WriteAttribute(int indentLevel, string attributeName, params string[] attributeParams) { var aParams = string.Empty; if (attributeParams.Any()) @@ -90,7 +90,7 @@ public void WriteAttribute(int indentLevel, string attributeName, params string[ /// Génère un record au lieu d'une classe. /// Liste des interfaces implémentées. /// Paramètres (si constructeur principal). - public void WriteClassDeclaration(string name, string? inheritedClass, bool isRecord, string[]? ifList = null, string? parameters = null) + public virtual void WriteClassDeclaration(string name, string? inheritedClass, bool isRecord, string[]? ifList = null, string? parameters = null) { if (string.IsNullOrEmpty(name)) { @@ -165,7 +165,7 @@ public void WriteLine(string? value = null) /// /// Niveau d'indentation. /// Valeur à écrire dans le flux. - public void WriteLine(int indentationLevel, string value) + public virtual void WriteLine(int indentationLevel, string value) { var indentValue = GetIdentValue(indentationLevel); value = value.Replace("\r\n", "\r\n" + indentValue); @@ -176,7 +176,7 @@ public void WriteLine(int indentationLevel, string value) /// Retourne le code associé à la déclaration d'un namespace. /// /// Valeur du namespace. - public void WriteNamespace(string value) + public virtual void WriteNamespace(string value) { WriteLine($"namespace {value};"); WriteLine(); @@ -188,7 +188,7 @@ public void WriteNamespace(string value) /// Nom du paramètre. /// Valeur du paramètre. /// Niveau d'indentation. - public void WriteParam(string paramName, string value, int indent = 1) + public virtual void WriteParam(string paramName, string value, int indent = 1) { if (!string.IsNullOrEmpty(paramName) && !string.IsNullOrEmpty(value)) { @@ -201,7 +201,7 @@ public void WriteParam(string paramName, string value, int indent = 1) /// /// Niveau d'indention. /// Description du returns. - public void WriteReturns(int indentationLevel, string value) + public virtual void WriteReturns(int indentationLevel, string value) { if (!string.IsNullOrEmpty(value)) { @@ -223,7 +223,7 @@ public void WriteSummary(string value) /// /// Niveau d'indentation. /// Valeur à écrire. - public void WriteSummary(int indentationLevel, string value) + public virtual void WriteSummary(int indentationLevel, string value) { if (!string.IsNullOrEmpty(value)) { @@ -237,7 +237,7 @@ public void WriteSummary(int indentationLevel, string value) /// Niveau d'indentation. /// Nom du paramètre. /// Valeur du paramètre. - public void WriteTypeParam(int indentationLevel, string paramName, string value) + public virtual void WriteTypeParam(int indentationLevel, string paramName, string value) { if (!string.IsNullOrEmpty(paramName) && !string.IsNullOrEmpty(value)) { @@ -249,7 +249,7 @@ public void WriteTypeParam(int indentationLevel, string paramName, string value) /// Retourne le code associé à la déclaration d'un Using. /// /// Nom de la classe/namespace à importer. - public void WriteUsings(params string[] nsNames) + public virtual void WriteUsings(params string[] nsNames) { var systemUsings = nsNames.Where(name => name.StartsWith("System")); var otherUsings = nsNames.Except(systemUsings); @@ -267,7 +267,7 @@ public void WriteUsings(params string[] nsNames) /// Description du paramètre. /// Tag XML. /// Code généré. - private static string LoadParam(string paramName, string value, string tag) + protected static string LoadParam(string paramName, string value, string tag) { if (string.IsNullOrEmpty(paramName)) { @@ -320,7 +320,7 @@ private static string LoadParam(string paramName, string value, string tag) /// /// Description de la valeur retournée. /// Code généré. - private static string LoadReturns(string value) + protected static string LoadReturns(string value) { if (string.IsNullOrEmpty(value)) { @@ -344,7 +344,7 @@ private static string LoadReturns(string value) /// /// Contenu du commentaire. /// Code généré. - private static string LoadSummary(string summary) + protected static string LoadSummary(string summary) { if (string.IsNullOrEmpty(summary)) { @@ -380,7 +380,7 @@ private static string LoadSummary(string summary) /// /// Niveau d'indention. /// Identation. - private string GetIdentValue(int indentationLevel) + protected string GetIdentValue(int indentationLevel) { var indentValue = string.Empty; for (var i = 0; i < indentationLevel; ++i) diff --git a/TopModel.Generator.Csharp/CsharpConfig.cs b/TopModel.Generator.Csharp/CsharpConfig.cs index 767b2c12..edfe66df 100644 --- a/TopModel.Generator.Csharp/CsharpConfig.cs +++ b/TopModel.Generator.Csharp/CsharpConfig.cs @@ -220,7 +220,7 @@ public override bool CanClassUseEnums(Class classe, IEnumerable? availabl return EnumsForStaticReferences && base.CanClassUseEnums(classe, availableClasses, prop); } - public string GetApiPath(ModelFile file, string tag, bool withControllers = false) + public virtual string GetApiPath(ModelFile file, string tag, bool withControllers = false) { return Path.Combine( OutputDirectory, @@ -229,7 +229,7 @@ public string GetApiPath(ModelFile file, string tag, bool withControllers = fals ResolveVariables(ApiFilePath, tag: tag, module: file.Namespace.ModulePath)); } - public string GetClassFileName(Class classe, string tag) + public virtual string GetClassFileName(Class classe, string tag) { return Path.Combine( OutputDirectory, @@ -238,7 +238,7 @@ public string GetClassFileName(Class classe, string tag) (classe.Abstract ? "I" : string.Empty) + classe.NamePascal + ".cs"); } - public string GetConvertedValue(string value, Domain? fromDomain, Domain? toDomain, bool nullableValueType) + public virtual string GetConvertedValue(string value, Domain? fromDomain, Domain? toDomain, bool nullableValueType) { if (nullableValueType && fromDomain != null && toDomain != null) { @@ -256,7 +256,7 @@ public string GetConvertedValue(string value, Domain? fromDomain, Domain? toDoma return GetConvertedValue(value, fromDomain, toDomain); } - public string GetDataFlowFilePath(DataFlow df, string tag) + public virtual string GetDataFlowFilePath(DataFlow df, string tag) { return Path.Combine( OutputDirectory, @@ -265,7 +265,7 @@ public string GetDataFlowFilePath(DataFlow df, string tag) $"{df.Name.ToPascalCase()}Flow.cs"); } - public string GetDataFlowRegistrationFilePath(DataFlow df, string tag) + public virtual string GetDataFlowRegistrationFilePath(DataFlow df, string tag) { return Path.Combine( OutputDirectory, @@ -274,7 +274,7 @@ public string GetDataFlowRegistrationFilePath(DataFlow df, string tag) $"ServiceExtensions.cs"); } - public string GetDbContextFilePath(string tag) + public virtual string GetDbContextFilePath(string tag) { return Path.Combine( OutputDirectory, @@ -288,18 +288,18 @@ public string GetDbContextFilePath(string tag) /// /// tag /// Nom. - public string GetDbContextName(string tag) + public virtual string GetDbContextName(string tag) { return ResolveVariables(DbContextName, tag: tag).Replace(".", string.Empty); } - public string GetDbContextNamespace(string tag) + public virtual string GetDbContextNamespace(string tag) { return ResolveVariables(DbContextPath!, tag: tag) .ToNamespace(); } - public string GetMapperFilePath((Class Class, FromMapper Mapper) mapper, string tag) + public virtual string GetMapperFilePath((Class Class, FromMapper Mapper) mapper, string tag) { var (ns, modelPath) = GetMapperLocation(mapper, tag); return Path.Combine( @@ -309,7 +309,7 @@ public string GetMapperFilePath((Class Class, FromMapper Mapper) mapper, string $"{GetMapperName(ns, modelPath)}.cs"); } - public string GetMapperFilePath((Class Class, ClassMappings Mapper) mapper, string tag) + public virtual string GetMapperFilePath((Class Class, ClassMappings Mapper) mapper, string tag) { var (ns, modelPath) = GetMapperLocation(mapper, tag); return Path.Combine( @@ -319,7 +319,7 @@ public string GetMapperFilePath((Class Class, ClassMappings Mapper) mapper, stri $"{GetMapperName(ns, modelPath)}.cs"); } - public (Namespace Namespace, string ModelPath) GetMapperLocation((Class Class, FromMapper Mapper) mapper, string tag) + public virtual (Namespace Namespace, string ModelPath) GetMapperLocation((Class Class, FromMapper Mapper) mapper, string tag) { var pmp = NoPersistence(tag) ? NonPersistentModelPath : PersistentModelPath; if (MapperLocationPriority == Target.Persisted) @@ -354,7 +354,7 @@ public string GetMapperFilePath((Class Class, ClassMappings Mapper) mapper, stri } } - public (Namespace Namespace, string ModelPath) GetMapperLocation((Class Class, ClassMappings Mapper) mapper, string tag) + public virtual (Namespace Namespace, string ModelPath) GetMapperLocation((Class Class, ClassMappings Mapper) mapper, string tag) { var pmp = NoPersistence(tag) ? NonPersistentModelPath : PersistentModelPath; if (MapperLocationPriority == Target.Persisted) @@ -387,7 +387,7 @@ public string GetMapperFilePath((Class Class, ClassMappings Mapper) mapper, stri } } - public string GetMapperName(Namespace ns, string modelPath) + public virtual string GetMapperName(Namespace ns, string modelPath) { return $"{ns.ModuleFlat}{(modelPath == PersistentModelPath ? string.Empty : "DTO")}Mappers"; } @@ -398,7 +398,7 @@ public string GetMapperName(Namespace ns, string modelPath) /// La classe. /// Tag. /// Chemin. - public string GetModelPath(Class classe, string tag) + public virtual string GetModelPath(Class classe, string tag) { return ResolveVariables( GetModelPathRaw(classe, tag), @@ -412,7 +412,7 @@ public string GetModelPath(Class classe, string tag) /// L'endpoint. /// Tag. /// Namespace. - public string GetNamespace(Endpoint endpoint, string tag) + public virtual string GetNamespace(Endpoint endpoint, string tag) { return GetNamespace(endpoint.Namespace, Path.Combine(ApiRootPath, ApiFilePath), tag); } @@ -423,7 +423,7 @@ public string GetNamespace(Endpoint endpoint, string tag) /// Le flux de données. /// Tag. /// Namespace. - public string GetNamespace(DataFlow dataFlow, string tag) + public virtual string GetNamespace(DataFlow dataFlow, string tag) { return GetNamespace(dataFlow.ModelFile.Namespace, DataFlowsPath!, tag); } @@ -434,19 +434,19 @@ public string GetNamespace(DataFlow dataFlow, string tag) /// La classe. /// Tag. /// Namespace. - public string GetNamespace(Class classe, string tag) + public virtual string GetNamespace(Class classe, string tag) { return GetNamespace(classe.Namespace, GetModelPathRaw(classe, tag), tag); } - public string GetNamespace(Namespace ns, string modelPath, string tag) + public virtual string GetNamespace(Namespace ns, string modelPath, string tag) { return ResolveVariables(modelPath, tag: tag, module: ns.Module) .ToNamespace() .Replace(".Dto", string.Empty); } - public string GetReferenceAccessorName(Namespace ns, string tag) + public virtual string GetReferenceAccessorName(Namespace ns, string tag) { return ResolveVariables( ReferenceAccessorsName, @@ -454,7 +454,7 @@ public string GetReferenceAccessorName(Namespace ns, string tag) module: ns.ModuleFlat); } - public string GetReferenceImplementationFilePath(Namespace ns, string tag) + public virtual string GetReferenceImplementationFilePath(Namespace ns, string tag) { return Path.Combine( OutputDirectory, @@ -466,7 +466,7 @@ public string GetReferenceImplementationFilePath(Namespace ns, string tag) $"{GetReferenceAccessorName(ns, tag)}.cs"); } - public string GetReferenceImplementationNamespace(Namespace ns, string tag) + public virtual string GetReferenceImplementationNamespace(Namespace ns, string tag) { return ResolveVariables( ReferenceAccessorsImplementationPath, @@ -474,7 +474,7 @@ public string GetReferenceImplementationNamespace(Namespace ns, string tag) module: ns.Module).ToNamespace(); } - public string GetReferenceInterfaceFilePath(Namespace ns, string tag) + public virtual string GetReferenceInterfaceFilePath(Namespace ns, string tag) { return Path.Combine( OutputDirectory, @@ -486,7 +486,7 @@ public string GetReferenceInterfaceFilePath(Namespace ns, string tag) $"I{GetReferenceAccessorName(ns, tag)}.cs"); } - public string GetReferenceInterfaceNamespace(Namespace ns, string tag) + public virtual string GetReferenceInterfaceNamespace(Namespace ns, string tag) { return ResolveVariables( ReferenceAccessorsInterfacePath, @@ -494,7 +494,7 @@ public string GetReferenceInterfaceNamespace(Namespace ns, string tag) module: ns.Module).ToNamespace(); } - public string GetReturnTypeName(IProperty? prop) + public virtual string GetReturnTypeName(IProperty? prop) { if (prop == null) { @@ -507,7 +507,7 @@ public string GetReturnTypeName(IProperty? prop) : $"async Task<{typeName}>"; } - public string GetType(IProperty prop, IEnumerable? availableClasses = null, bool useClassForAssociation = false, bool nonNullable = false) + public virtual string GetType(IProperty prop, IEnumerable? availableClasses = null, bool useClassForAssociation = false, bool nonNullable = false) { var type = base.GetType(prop, availableClasses, useClassForAssociation); @@ -524,7 +524,7 @@ public override bool IsPersistent(Class classe, string tag) return base.IsPersistent(classe, tag) && !NoPersistence(tag); } - public bool IsValueType(IProperty prop, IEnumerable? availableClasses) + public virtual bool IsValueType(IProperty prop, IEnumerable? availableClasses) { return prop switch { @@ -537,12 +537,12 @@ AssociationProperty ap when CanClassUseEnums(ap.Association, availableClasses, a }; } - public bool NoPersistence(string tag) + public virtual bool NoPersistence(string tag) { return ResolveVariables(NoPersistenceParam ?? string.Empty, tag) == true.ToString(); } - public bool RequiredNonNullable(string tag) + public virtual bool RequiredNonNullable(string tag) { return ResolveVariables(RequiredNonNullableParam ?? string.Empty, tag) == true.ToString(); } @@ -552,12 +552,7 @@ protected override string GetEnumType(string className, string propName, bool is return $"{(isPrimaryKeyDef ? string.Empty : $"{className.ToPascalCase()}.")}{propName.ToPascalCase()}{(!propName.EndsWith('s') ? "s" : string.Empty)}"; } - protected override bool IsEnumNameValid(string name) - { - return base.IsEnumNameValid(name) && !name.Contains('-') && name.FirstOrDefault() != name.ToLower().FirstOrDefault(); - } - - private string GetModelPathRaw(Class classe, string tag) + protected virtual string GetModelPathRaw(Class classe, string tag) { return classe.Reference && ReferencesModelPath != null ? ReferencesModelPath @@ -565,4 +560,9 @@ private string GetModelPathRaw(Class classe, string tag) ? PersistentModelPath : NonPersistentModelPath; } + + protected override bool IsEnumNameValid(string name) + { + return base.IsEnumNameValid(name) && !name.Contains('-') && name.FirstOrDefault() != name.ToLower().FirstOrDefault(); + } } \ No newline at end of file diff --git a/TopModel.Generator.Csharp/DataFlowGenerator.cs b/TopModel.Generator.Csharp/DataFlowGenerator.cs index 2bb946f5..2aa8d6e0 100644 --- a/TopModel.Generator.Csharp/DataFlowGenerator.cs +++ b/TopModel.Generator.Csharp/DataFlowGenerator.cs @@ -24,32 +24,7 @@ public DataFlowGenerator(ILogger logger) public override string Name => "CSharpDataFlowGen"; - protected override void HandleFiles(IEnumerable files) - { - foreach (var file in files) - { - foreach (var dataFlow in file.DataFlows) - { - foreach (var (tag, fileName) in Config.Tags.Intersect(file.Tags) - .Select(tag => (tag, fileName: Config.GetDataFlowFilePath(dataFlow, tag))) - .DistinctBy(t => t.fileName)) - { - HandleDataFlow(fileName, dataFlow, tag); - HandleDataFlowPartial(fileName.Replace($"{Path.DirectorySeparatorChar}generated", string.Empty).Replace(".cs", ".partial.cs"), dataFlow, tag); - } - } - } - - foreach (var g in Files.Values.SelectMany(f => f.DataFlows) - .SelectMany(df => Config.Tags.Intersect(df.ModelFile.Tags) - .Select(tag => (tag, df, fileName: Config.GetDataFlowRegistrationFilePath(df, tag)))) - .GroupBy(g => g.fileName)) - { - HandleRegistrationFile(g.Key, g.Select(i => i.df), g.First().tag); - } - } - - private void HandleDataFlow(string fileName, DataFlow dataFlow, string tag) + protected virtual void HandleDataFlow(string fileName, DataFlow dataFlow, string tag) { int GetSourceNumber(DataFlowSource source) { @@ -292,7 +267,7 @@ string GetJoin(DataFlowSource source, DataFlowSource? targetSource = null) w.WriteLine("}"); } - private void HandleDataFlowPartial(string fileName, DataFlow dataFlow, string tag) + protected virtual void HandleDataFlowPartial(string fileName, DataFlow dataFlow, string tag) { if (!dataFlow.Sources.Any(s => s.Mode == DataFlowSourceMode.Partial) && !dataFlow.Hooks.Contains(FlowHook.AfterFlow) && !dataFlow.Hooks.Contains(FlowHook.BeforeFlow)) { @@ -346,7 +321,32 @@ private void HandleDataFlowPartial(string fileName, DataFlow dataFlow, string ta w.WriteLine("}"); } - private void HandleRegistrationFile(string fileName, IEnumerable flows, string tag) + protected override void HandleFiles(IEnumerable files) + { + foreach (var file in files) + { + foreach (var dataFlow in file.DataFlows) + { + foreach (var (tag, fileName) in Config.Tags.Intersect(file.Tags) + .Select(tag => (tag, fileName: Config.GetDataFlowFilePath(dataFlow, tag))) + .DistinctBy(t => t.fileName)) + { + HandleDataFlow(fileName, dataFlow, tag); + HandleDataFlowPartial(fileName.Replace($"{Path.DirectorySeparatorChar}generated", string.Empty).Replace(".cs", ".partial.cs"), dataFlow, tag); + } + } + } + + foreach (var g in Files.Values.SelectMany(f => f.DataFlows) + .SelectMany(df => Config.Tags.Intersect(df.ModelFile.Tags) + .Select(tag => (tag, df, fileName: Config.GetDataFlowRegistrationFilePath(df, tag)))) + .GroupBy(g => g.fileName)) + { + HandleRegistrationFile(g.Key, g.Select(i => i.df), g.First().tag); + } + } + + protected virtual void HandleRegistrationFile(string fileName, IEnumerable flows, string tag) { var firstFlow = flows.First(); using var w = new CSharpWriter(fileName, _logger); diff --git a/TopModel.Generator.Csharp/DbContextGenerator.cs b/TopModel.Generator.Csharp/DbContextGenerator.cs index 93a74a61..85bf2f3d 100644 --- a/TopModel.Generator.Csharp/DbContextGenerator.cs +++ b/TopModel.Generator.Csharp/DbContextGenerator.cs @@ -16,46 +16,7 @@ public DbContextGenerator(ILogger logger) public override string Name => "CSharpDbContextGen"; - protected override IEnumerable<(string FileType, string FileName)> GetFileNames(Class classe, string tag) - { - if (classe.IsPersistent && !classe.Abstract && !Config.NoPersistence(tag)) - { - yield return ("main", Config.GetDbContextFilePath(tag)); - - if (Config.UseEFComments) - { - yield return ("comments", Config.GetDbContextFilePath(tag).Replace(".cs", ".comments.cs")); - } - } - } - - protected override void HandleFile(string fileType, string fileName, string tag, IEnumerable classes) - { - var dbContextName = Config.GetDbContextName(tag); - var usings = new List { "Microsoft.EntityFrameworkCore" }; - var contextNs = Config.GetDbContextNamespace(tag); - - foreach (var ns in classes - .Concat(GetAssociationProperties(classes, tag).Select(ap => ap.AssociationProperty.Association)) - .Select(c => Config.GetNamespace(c, GetBestClassTag(c, tag))) - .Distinct()) - { - usings.Add(ns); - } - - var classList = classes.OrderBy(c => c.NamePascal).ToList(); - - if (fileType == "main") - { - HandleMainFile(fileName, tag, dbContextName, contextNs, usings, classList); - } - else - { - HandleCommentsFile(fileName, tag, dbContextName, contextNs, usings, classList); - } - } - - private IEnumerable<(IProperty Property, AssociationProperty AssociationProperty)> GetAssociationProperties(IEnumerable classes, string tag) + protected virtual IEnumerable<(IProperty Property, AssociationProperty AssociationProperty)> GetAssociationProperties(IEnumerable classes, string tag) { return classes .Distinct() @@ -72,7 +33,20 @@ protected override void HandleFile(string fileType, string fileName, string tag, .Where(p => Classes.Contains(p.ap.Association) && Config.IsPersistent(p.ap.Association, GetBestClassTag(p.ap.Association, tag))); } - private void HandleCommentsFile(string fileName, string tag, string dbContextName, string contextNs, IList usings, IList classes) + protected override IEnumerable<(string FileType, string FileName)> GetFileNames(Class classe, string tag) + { + if (classe.IsPersistent && !classe.Abstract && !Config.NoPersistence(tag)) + { + yield return ("main", Config.GetDbContextFilePath(tag)); + + if (Config.UseEFComments) + { + yield return ("comments", Config.GetDbContextFilePath(tag).Replace(".cs", ".comments.cs")); + } + } + } + + protected virtual void HandleCommentsFile(string fileName, string tag, string dbContextName, string contextNs, IList usings, IList classes) { using var cw = new CSharpWriter(fileName, _logger); @@ -107,7 +81,33 @@ private void HandleCommentsFile(string fileName, string tag, string dbContextNam cw.WriteLine("}"); } - private void HandleMainFile(string fileName, string tag, string dbContextName, string contextNs, List usings, List classes) + protected override void HandleFile(string fileType, string fileName, string tag, IEnumerable classes) + { + var dbContextName = Config.GetDbContextName(tag); + var usings = new List { "Microsoft.EntityFrameworkCore" }; + var contextNs = Config.GetDbContextNamespace(tag); + + foreach (var ns in classes + .Concat(GetAssociationProperties(classes, tag).Select(ap => ap.AssociationProperty.Association)) + .Select(c => Config.GetNamespace(c, GetBestClassTag(c, tag))) + .Distinct()) + { + usings.Add(ns); + } + + var classList = classes.OrderBy(c => c.NamePascal).ToList(); + + if (fileType == "main") + { + HandleMainFile(fileName, tag, dbContextName, contextNs, usings, classList); + } + else + { + HandleCommentsFile(fileName, tag, dbContextName, contextNs, usings, classList); + } + } + + protected virtual void HandleMainFile(string fileName, string tag, string dbContextName, string contextNs, List usings, List classes) { using var w = new CSharpWriter(fileName, _logger); diff --git a/TopModel.Generator.Csharp/MapperGenerator.cs b/TopModel.Generator.Csharp/MapperGenerator.cs index 95912b7c..c9a554d1 100644 --- a/TopModel.Generator.Csharp/MapperGenerator.cs +++ b/TopModel.Generator.Csharp/MapperGenerator.cs @@ -26,6 +26,18 @@ protected override string GetFileName((Class Classe, ClassMappings Mapper) mappe return Config.GetMapperFilePath(mapper, tag); } + protected virtual string GetSourceMapping(IProperty property) + { + if (property is CompositionProperty cp) + { + return $"{cp.NamePascal}?.{cp.CompositionPrimaryKey?.NamePascal}"; + } + else + { + return property.NamePascal; + } + } + protected override void HandleFile(string fileName, string tag, IList<(Class Classe, FromMapper Mapper)> fromMappers, IList<(Class Classe, ClassMappings Mapper)> toMappers) { using var w = new CSharpWriter(fileName, _logger); @@ -536,16 +548,4 @@ protected override bool IsPersistent(Class classe) return (classe.Tags.Intersect(Config.MapperTagsOverrides).Any() || classe.IsPersistent) && (Config.ReferencesModelPath == null || !classe.Reference); } - - private static string GetSourceMapping(IProperty property) - { - if (property is CompositionProperty cp) - { - return $"{cp.NamePascal}?.{cp.CompositionPrimaryKey?.NamePascal}"; - } - else - { - return property.NamePascal; - } - } } \ No newline at end of file diff --git a/TopModel.Generator.Csharp/ReferenceAccessorGenerator.cs b/TopModel.Generator.Csharp/ReferenceAccessorGenerator.cs index 0b088966..3118f1a7 100644 --- a/TopModel.Generator.Csharp/ReferenceAccessorGenerator.cs +++ b/TopModel.Generator.Csharp/ReferenceAccessorGenerator.cs @@ -16,39 +16,13 @@ public ReferenceAccessorGenerator(ILogger logger) public override string Name => "CSharpRefAccessGen"; - protected override IEnumerable<(string FileType, string FileName)> GetFileNames(Class classe, string tag) - { - if (classe.Reference) - { - yield return ("interface", Config.GetReferenceInterfaceFilePath(classe.Namespace, tag)); - if (!Config.NoPersistence(tag) && (classe.IsPersistent || classe.Values.Any())) - { - yield return ("implementation", Config.GetReferenceImplementationFilePath(classe.Namespace, tag)); - } - } - } - - protected override void HandleFile(string fileType, string fileName, string tag, IEnumerable classes) - { - var classList = classes - .OrderBy(x => Config.DbContextPath == null ? $"{x.NamePascal}List" : x.PluralNamePascal, StringComparer.Ordinal) - .ToList(); - - if (fileType == "interface") - { - GenerateReferenceAccessorsInterface(fileName, tag, classList); - } - else - { - GenerateReferenceAccessorsImplementation(fileName, tag, classList); - } - } - /// /// Génère l'implémentation des ReferenceAccessors. /// - /// Liste de ModelClass. - private void GenerateReferenceAccessorsImplementation(string fileName, string tag, List classList) + /// Nom du fichier cible. + /// Tag du fichier cible. + /// Liste de classes à générer. + protected virtual void GenerateReferenceAccessorsImplementation(string fileName, string tag, List classList) { var ns = classList.First().Namespace; @@ -186,8 +160,10 @@ private void GenerateReferenceAccessorsImplementation(string fileName, string ta /// /// Génère l'interface déclarant les ReferenceAccessors d'un namespace. /// - /// Liste de ModelClass. - private void GenerateReferenceAccessorsInterface(string fileName, string tag, IEnumerable classList) + /// Nom du fichier cible. + /// Tag du fichier cible. + /// Liste de classes à générer. + protected virtual void GenerateReferenceAccessorsInterface(string fileName, string tag, IEnumerable classList) { var ns = classList.First().Namespace; @@ -235,12 +211,40 @@ private void GenerateReferenceAccessorsInterface(string fileName, string tag, IE w.WriteLine("}"); } + protected override IEnumerable<(string FileType, string FileName)> GetFileNames(Class classe, string tag) + { + if (classe.Reference) + { + yield return ("interface", Config.GetReferenceInterfaceFilePath(classe.Namespace, tag)); + if (!Config.NoPersistence(tag) && (classe.IsPersistent || classe.Values.Any())) + { + yield return ("implementation", Config.GetReferenceImplementationFilePath(classe.Namespace, tag)); + } + } + } + + protected override void HandleFile(string fileType, string fileName, string tag, IEnumerable classes) + { + var classList = classes + .OrderBy(x => Config.DbContextPath == null ? $"{x.NamePascal}List" : x.PluralNamePascal, StringComparer.Ordinal) + .ToList(); + + if (fileType == "interface") + { + GenerateReferenceAccessorsInterface(fileName, tag, classList); + } + else + { + GenerateReferenceAccessorsImplementation(fileName, tag, classList); + } + } + /// /// Retourne le code associé au corps de l'implémentation d'un service de type ReferenceAccessor. /// /// Type chargé par le ReferenceAccessor. /// Code généré. - private string LoadReferenceAccessorBody(Class classe) + protected virtual string LoadReferenceAccessorBody(Class classe) { if (!classe.IsPersistent) {