From 0cf7404b85c4bfc9dcdf95834f1bb1f772351062 Mon Sep 17 00:00:00 2001 From: JacobTech Date: Fri, 22 Dec 2023 11:20:45 -0500 Subject: [PATCH] Generation Update A few changes to start adding more generation methods. --- .../JsonIgnoreIndexAttribute.cs | 12 ++ .../JsonSubObjectAttribute.cs | 14 ++ .../JsonTableRowAttribute.cs | 14 ++ .../JsonTableRowGenerator.cs | 130 ++++++++++++++++++ .../ServerDatabase.SourceGenerator.csproj | 2 +- .../TableRowGenerator.cs | 1 - 6 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 ServerDatabase.SourceGenerator/JsonIgnoreIndexAttribute.cs create mode 100644 ServerDatabase.SourceGenerator/JsonSubObjectAttribute.cs create mode 100644 ServerDatabase.SourceGenerator/JsonTableRowAttribute.cs create mode 100644 ServerDatabase.SourceGenerator/JsonTableRowGenerator.cs diff --git a/ServerDatabase.SourceGenerator/JsonIgnoreIndexAttribute.cs b/ServerDatabase.SourceGenerator/JsonIgnoreIndexAttribute.cs new file mode 100644 index 0000000..ef55461 --- /dev/null +++ b/ServerDatabase.SourceGenerator/JsonIgnoreIndexAttribute.cs @@ -0,0 +1,12 @@ +namespace ServerDatabase.SourceGenerator; + +[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] +public sealed class JsonIgnoreIndexAttribute : Attribute +{ + public JsonIgnoreIndexAttribute(int index = 0) + { + this.Index = index; + } + + public int Index { get; private set; } = 0; +} \ No newline at end of file diff --git a/ServerDatabase.SourceGenerator/JsonSubObjectAttribute.cs b/ServerDatabase.SourceGenerator/JsonSubObjectAttribute.cs new file mode 100644 index 0000000..0be539a --- /dev/null +++ b/ServerDatabase.SourceGenerator/JsonSubObjectAttribute.cs @@ -0,0 +1,14 @@ +namespace ServerDatabase.SourceGenerator; + +[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] +public sealed class JsonSubObjectAttribute : Attribute +{ + public JsonSubObjectAttribute(Type type, int index = 0) + { + this.Type = type; + this.Index = index; + } + + public int Index { get; private set; } = 0; + public Type Type { get; private set; } +} \ No newline at end of file diff --git a/ServerDatabase.SourceGenerator/JsonTableRowAttribute.cs b/ServerDatabase.SourceGenerator/JsonTableRowAttribute.cs new file mode 100644 index 0000000..69579c5 --- /dev/null +++ b/ServerDatabase.SourceGenerator/JsonTableRowAttribute.cs @@ -0,0 +1,14 @@ +namespace ServerDatabase.SourceGenerator; + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public sealed class JsonTableRowAttribute : Attribute +{ + public JsonTableRowAttribute(Type type, int index = 0) + { + this.Type = type; + this.Index = index; + } + + public int Index { get; private set; } = 0; + public Type Type { get; private set; } +} \ No newline at end of file diff --git a/ServerDatabase.SourceGenerator/JsonTableRowGenerator.cs b/ServerDatabase.SourceGenerator/JsonTableRowGenerator.cs new file mode 100644 index 0000000..91bba2c --- /dev/null +++ b/ServerDatabase.SourceGenerator/JsonTableRowGenerator.cs @@ -0,0 +1,130 @@ +using System.Diagnostics; +using System.Reflection; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Text; +using TypeInfo = Microsoft.CodeAnalysis.TypeInfo; + +namespace ServerDatabase.SourceGenerator; + +[Generator] +public class JsonTableRowGenerator : ISourceGenerator +{ + public void Initialize(GeneratorInitializationContext context) + { +#if DEBUG + if (!Debugger.IsAttached) Debugger.Launch(); +#endif + } + + public void Execute(GeneratorExecutionContext context) + { + try + { + INamedTypeSymbol? attributeSymbol = context.Compilation.GetTypeByMetadataName(typeof(JsonTableRowAttribute).FullName); + + IEnumerable classWithAttributes = context.Compilation.SyntaxTrees.Where(st => st.GetRoot().DescendantNodes().OfType() + .Any(p => p.DescendantNodes().OfType().Any())); + + foreach (SyntaxTree? tree in classWithAttributes) + { + if (tree is null) continue; + SemanticModel semanticModel = context.Compilation.GetSemanticModel(tree); + foreach (ClassDeclarationSyntax? declaredClass in tree.GetRoot().DescendantNodes().OfType().Where(cd => cd.DescendantNodes().OfType().Any())) + { + if (declaredClass is null) continue; + List? nodes = declaredClass + .DescendantNodes() + .OfType() + .FirstOrDefault(a => a.DescendantTokens().Any(dt => dt.IsKind(SyntaxKind.IdentifierToken) && dt.Parent is not null && semanticModel.GetTypeInfo(dt.Parent).Type is not null && semanticModel.GetTypeInfo(dt.Parent).Type.Name == attributeSymbol.Name)) + ?.DescendantTokens() + ?.Where(dt => dt.IsKind(SyntaxKind.IdentifierToken)) + ?.ToList(); + + if(nodes == null) + { + continue; + } + + TypeInfo relatedClass = semanticModel.GetTypeInfo(nodes.Last().Parent); + + StringBuilder generatedClass = this.GenerateClass(tree.GetRoot().DescendantNodes().OfType().First().Name.ToString(), declaredClass); + + foreach(IPropertySymbol? classProperty in relatedClass.Type.GetMembers().OfType()) + { + this.GenerateProperty(classProperty, ref generatedClass); + } + + this.CloseClass(generatedClass); + + context.AddSource($"{declaredClass.Identifier}_{relatedClass.Type.Name}.g.cs", SourceText.From(generatedClass.ToString(), Encoding.UTF8)); + } + } + } + catch (Exception e) + { + context.AddSource("teste.g.cs", SourceText.From(@$"// +using System; +namespace ServerDatabase.SourceGenerator.Generated +{{ + public class bobe + {{ + public string e = @""{e}""; + }} +}}", Encoding.UTF8)); + } + return; + } + + private void GenerateProperty(IPropertySymbol prop, ref StringBuilder builder) + { + prop.GetAttributes().SelectMany(s => s.NamedArguments); + string bad = prop.Type.ToString(); + Console.WriteLine(prop); + bad = bad.Replace("ServerDatabase.TableColumn<", ""); + bad = bad.Remove(bad.LastIndexOf('>')); + if (bad.ToLower() == "byte[]") bad = "string"; + EqualsValueClauseSyntax? equalsSyntax = prop.DeclaringSyntaxReferences[0].GetSyntax() switch + { + PropertyDeclarationSyntax property => property.Initializer, + VariableDeclaratorSyntax variable => variable.Initializer, + _ => throw new Exception("Unknown declaration syntax") + }; + + // If the property/field has an initializer + if (equalsSyntax is not null) + { + string valueAsStr = equalsSyntax.Value.ToString().Split('"')[1]; + builder.AppendLine($" [JsonInclude]"); + builder.AppendLine($" [JsonPropertyName(\"{valueAsStr}\")]"); + builder.AppendLine($" public {bad} {prop.Name} {{ get; set; }}"); + } + + } + + private StringBuilder GenerateClass(string n, ClassDeclarationSyntax og) + { + StringBuilder sb = new StringBuilder(); + sb.Append(@$"// +using System; + +namespace {n} +{{ + public partial class " + og.Identifier); + + sb.Append(@" + { +"); + + return sb; + } + + private void CloseClass(StringBuilder generatedClass) + { + generatedClass.Append( + @" } +}"); + } +} \ No newline at end of file diff --git a/ServerDatabase.SourceGenerator/ServerDatabase.SourceGenerator.csproj b/ServerDatabase.SourceGenerator/ServerDatabase.SourceGenerator.csproj index 5aa00f2..77193ab 100644 --- a/ServerDatabase.SourceGenerator/ServerDatabase.SourceGenerator.csproj +++ b/ServerDatabase.SourceGenerator/ServerDatabase.SourceGenerator.csproj @@ -6,7 +6,7 @@ enable netstandard2.0 true - 1.0.1 + 1.0.2-alpha10 Server Database Source Generator JacobTech diff --git a/ServerDatabase.SourceGenerator/TableRowGenerator.cs b/ServerDatabase.SourceGenerator/TableRowGenerator.cs index 657f091..493c6bf 100644 --- a/ServerDatabase.SourceGenerator/TableRowGenerator.cs +++ b/ServerDatabase.SourceGenerator/TableRowGenerator.cs @@ -59,7 +59,6 @@ public class TableRowGenerator : ISourceGenerator this.CloseClass(generatedClass); context.AddSource($"{declaredClass.Identifier}_{relatedClass.Type.Name}.g.cs", SourceText.From(generatedClass.ToString(), Encoding.UTF8)); - //context.AddSource($"{declaredClass.Identifier}_{relatedClass.Type.Name}_goooddddd.g.cs", SourceText.From(generatedClass.ToString().Replace("partial ", "").Replace(declaredClass.Identifier.ToString(), declaredClass.Identifier.ToString() + "GODDD"), Encoding.UTF8)); } } }