using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; namespace CSV_Metrics_Logger_Generator; [Generator] public class CSVConverterGenerator : ISourceGenerator { private const string ARRAY_DELIMITER = ", "; #region Implementation of ISourceGenerator public void Initialize(GeneratorInitializationContext context) { context.RegisterForSyntaxNotifications(() => new SyntaxReceiver()); } public void Execute(GeneratorExecutionContext context) { if (context.SyntaxReceiver is not SyntaxReceiver receiver) return; foreach (var dataStructure in receiver.DataStructures) this.ProcessStructure(context, dataStructure); } private void ProcessStructure(GeneratorExecutionContext context, TypeDeclarationSyntax dataStructure) { var accessModifiers = string.Join(' ', dataStructure.Modifiers.Select(n => n.Text)); var declarationType = dataStructure switch { RecordDeclarationSyntax => "record struct", StructDeclarationSyntax => "struct", _ => string.Empty }; var namespaceName = this.GetNamespaceFrom(dataStructure); var parameterProperties = dataStructure.ParameterList?.Parameters.Select(n => n.Identifier.ValueText).ToList() ?? []; var bodyProperties = dataStructure.Members.OfType().Select(n => n.Identifier.ValueText).ToList(); var allProperties = new List(parameterProperties); allProperties.AddRange(bodyProperties); var numberProperties = allProperties.Count; var header = string.Join(ARRAY_DELIMITER, allProperties.Select(n => $"\"{n}\"")); var allFieldsString = string.Join(ARRAY_DELIMITER, allProperties.Select(n => $"this.{n}.ToString(CultureInfo.InvariantCulture)")); var sourceCode = SourceText.From( $$""" using System.Globalization; using CSV_Metrics_Logger; namespace {{namespaceName}}; {{accessModifiers}} {{declarationType}} {{dataStructure.Identifier}} : IConvertToCSV { public uint GetCSVColumnCount() { return (uint){{numberProperties}}; } public IList GetCSVHeaders() { return [ {{header}} ]; } public IList ConvertToCSVDataLine() { return [ {{allFieldsString}} ]; } } """, Encoding.UTF8); context.AddSource($"{dataStructure.Identifier}.Generated.cs", sourceCode); } private string GetNamespaceFrom(SyntaxNode? node) => node switch { BaseNamespaceDeclarationSyntax namespaceDeclarationSyntax => namespaceDeclarationSyntax.Name.ToString(), null => string.Empty, _ => this.GetNamespaceFrom(node.Parent) }; #endregion }