mirror of
				https://gitlab.com/Kwoth/nadekobot.git
				synced 2025-11-04 00:34:26 -05:00 
			
		
		
		
	- Added NadekoBot.Generators projects which will contain source generators
- Implemented initial version of the response strings source generator - Creates a class with property names equivalent to key names in responses.en-US.json - Each Property has struct type (with generic type parameters matching the number of string format placeholders) for type safe GetText implementation - Struct types are readonly refs as they should be ephermal, and only used to pass string keys to GetText
This commit is contained in:
		
							
								
								
									
										159
									
								
								src/NadekoBot.Generators/LocalizedStringsGenerator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								src/NadekoBot.Generators/LocalizedStringsGenerator.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,159 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.CodeDom.Compiler;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
using Microsoft.CodeAnalysis;
 | 
			
		||||
using Microsoft.CodeAnalysis.Text;
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Generators
 | 
			
		||||
{
 | 
			
		||||
    internal class FieldData
 | 
			
		||||
    {
 | 
			
		||||
        public string Type { get; set; }
 | 
			
		||||
        public string Name { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    [Generator]
 | 
			
		||||
    public class LocalizedStringsGenerator : ISourceGenerator
 | 
			
		||||
    {
 | 
			
		||||
        private const string LocStrSource = @"namespace NadekoBot
 | 
			
		||||
{
 | 
			
		||||
    public readonly ref struct LocStr
 | 
			
		||||
    {
 | 
			
		||||
        public readonly string Key;
 | 
			
		||||
        
 | 
			
		||||
        public LocStr(string key)
 | 
			
		||||
        {
 | 
			
		||||
            Key = key;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public static implicit operator LocStr(string data)
 | 
			
		||||
            => new LocStr(data);    
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public readonly ref struct LocStr<T1>
 | 
			
		||||
    {
 | 
			
		||||
        public readonly string Key;
 | 
			
		||||
        
 | 
			
		||||
        public LocStr(string key)
 | 
			
		||||
        {
 | 
			
		||||
            Key = key;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public static implicit operator LocStr<T1>(string data)
 | 
			
		||||
            => new LocStr<T1>(data);    
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public readonly ref struct LocStr<T1, T2>
 | 
			
		||||
    {
 | 
			
		||||
        public readonly string Key;
 | 
			
		||||
        
 | 
			
		||||
        public LocStr(string key)
 | 
			
		||||
        {
 | 
			
		||||
            Key = key;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public static implicit operator LocStr<T1, T2>(string data)
 | 
			
		||||
            => new LocStr<T1, T2>(data);    
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public readonly ref struct LocStr<T1, T2, T3>
 | 
			
		||||
    {
 | 
			
		||||
        public readonly string Key;
 | 
			
		||||
        
 | 
			
		||||
        public LocStr(string key)
 | 
			
		||||
        {
 | 
			
		||||
            Key = key;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public static implicit operator LocStr<T1, T2, T3>(string data)
 | 
			
		||||
            => new LocStr<T1, T2, T3>(data);    
 | 
			
		||||
    }
 | 
			
		||||
}";
 | 
			
		||||
        
 | 
			
		||||
        public void Initialize(GeneratorInitializationContext context)
 | 
			
		||||
        {
 | 
			
		||||
            
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Execute(GeneratorExecutionContext context)
 | 
			
		||||
        {
 | 
			
		||||
            var file = context.AdditionalFiles.First(x => x.Path.EndsWith("responses.en-US.json"));
 | 
			
		||||
 | 
			
		||||
            var fields = GetFields(file.GetText()?.ToString());
 | 
			
		||||
 | 
			
		||||
            using (var stringWriter = new StringWriter())
 | 
			
		||||
            using (var sw = new IndentedTextWriter(stringWriter))
 | 
			
		||||
            {
 | 
			
		||||
                sw.WriteLine("namespace NadekoBot");
 | 
			
		||||
                sw.WriteLine("{");
 | 
			
		||||
                sw.Indent++;
 | 
			
		||||
 | 
			
		||||
                sw.WriteLine("public static class Strs");
 | 
			
		||||
                sw.WriteLine("{");
 | 
			
		||||
                sw.Indent++;
 | 
			
		||||
 | 
			
		||||
                foreach (var field in fields)
 | 
			
		||||
                {
 | 
			
		||||
                    sw.WriteLine($"public static {field.Type} {field.Name} => \"{field.Name}\";");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                sw.Indent--;
 | 
			
		||||
                sw.WriteLine("}");
 | 
			
		||||
                sw.Indent--;
 | 
			
		||||
                sw.WriteLine("}");
 | 
			
		||||
                
 | 
			
		||||
                
 | 
			
		||||
                sw.Flush();
 | 
			
		||||
                context.AddSource("Strs.cs", stringWriter.ToString());
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            context.AddSource("LocStr.cs", LocStrSource);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private List<FieldData> GetFields(string dataText)
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(dataText))
 | 
			
		||||
                throw new ArgumentNullException(nameof(dataText));
 | 
			
		||||
            
 | 
			
		||||
            var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(dataText);
 | 
			
		||||
 | 
			
		||||
            var list = new List<FieldData>();
 | 
			
		||||
            foreach (var entry in data)
 | 
			
		||||
            {
 | 
			
		||||
                list.Add(new FieldData()
 | 
			
		||||
                {
 | 
			
		||||
                    Type = GetFieldType(entry.Value),
 | 
			
		||||
                    Name = entry.Key,
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return list;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private string GetFieldType(string value)
 | 
			
		||||
        {
 | 
			
		||||
            var matches = Regex.Matches(value, @"{(?<num>\d)}");
 | 
			
		||||
            int max = 0;
 | 
			
		||||
            foreach (Match match in matches)
 | 
			
		||||
            {
 | 
			
		||||
                max = Math.Max(max, int.Parse(match.Groups["num"].Value));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (max == 0)
 | 
			
		||||
                return "LocStr";
 | 
			
		||||
            if (max == 1)
 | 
			
		||||
                return "LocStr<string>";
 | 
			
		||||
            if (max == 2)
 | 
			
		||||
                return "LocStr<string, string>";
 | 
			
		||||
            if (max == 3)
 | 
			
		||||
                return "LocStr<string, string, string>";
 | 
			
		||||
 | 
			
		||||
            return "!Error";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user