diff --git a/Package/build/Polonium.Tasks.props b/Package/build/Polonium.Tasks.props index 99f8023..5173e2a 100644 --- a/Package/build/Polonium.Tasks.props +++ b/Package/build/Polonium.Tasks.props @@ -12,4 +12,8 @@ TaskName="GenerateTextureSetTask" AssemblyFile="$(TasksAssembly)" /> + \ No newline at end of file diff --git a/src/PoloniumTask.cs b/src/PoloniumTask.cs new file mode 100644 index 0000000..eeda371 --- /dev/null +++ b/src/PoloniumTask.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Microsoft.Build.Utilities; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Polonium.Tasks; + +public abstract class PoloniumTask : Task +{ + protected static bool HasGetterOnly(PropertyDeclarationSyntax property) + { + var registryAttribute = property.AttributeLists + .SelectMany(a => a.Attributes) + .FirstOrDefault(a => a.Name.ToString() == "RegistryPassThrough"); + + if (registryAttribute?.ArgumentList != null) + { + foreach (var argument in registryAttribute.ArgumentList.Arguments) + { + if (argument.Expression is LiteralExpressionSyntax literal) + { + if (literal.Kind() == SyntaxKind.TrueLiteralExpression) + { + return true; + } + if (literal.Kind() == SyntaxKind.FalseLiteralExpression) + { + return false; + } + } + } + } + return false; + } + protected static string GetDisplayName(ClassDeclarationSyntax cls) + { + string name = cls.Identifier.Text; + SyntaxNode node = cls.Parent; + while (node is not null) + { + if(node is NamespaceDeclarationSyntax ns) + name = ns.Name.ToString() + "." + name; + else if (node is FileScopedNamespaceDeclarationSyntax fs) + name = fs.Name.ToString() + "." + name; + node = node.Parent; + } + return name; + } + protected static string GetRelativePath(string basePath, string fullPath) + { + Uri baseUri = new Uri(basePath.EndsWith(Path.DirectorySeparatorChar.ToString()) ? basePath : basePath + Path.DirectorySeparatorChar); + Uri fullUri = new Uri(fullPath); + return Uri.UnescapeDataString(baseUri.MakeRelativeUri(fullUri).ToString().Replace('/', Path.DirectorySeparatorChar)); + } + protected static string GetDisplayName(TypeSyntax type) + { + if (type is IdentifierNameSyntax identifierName) + return identifierName.Identifier.Text; + if (type is QualifiedNameSyntax qualifiedName) + return GetDisplayName(qualifiedName.Left) + "." + GetDisplayName(qualifiedName.Right); + if (type is GenericNameSyntax genericName) + { + string typeName = genericName.Identifier.Text; + string typeArguments = string.Join(", ", genericName.TypeArgumentList.Arguments.Select(GetDisplayName)); + return $"{typeName}<{typeArguments}>"; + } + if (type is AliasQualifiedNameSyntax aliasQualifiedName) + return $"{aliasQualifiedName.Alias.Identifier.Text}::{GetDisplayName(aliasQualifiedName.Name)}"; + if (type is PredefinedTypeSyntax predefinedType) + return predefinedType.Keyword.Text; + return type.ToString(); + } + protected static IEnumerable GetUsings(string code) + { + SyntaxTree tree = CSharpSyntaxTree.ParseText(code); + CompilationUnitSyntax root = tree.GetCompilationUnitRoot(); + + return root.Usings + .Select(u => u.ToString()); + } + +} \ No newline at end of file diff --git a/src/GenerateProxyNodesTask.cs b/src/Tasks/GenerateProxyNodesTask.cs similarity index 88% rename from src/GenerateProxyNodesTask.cs rename to src/Tasks/GenerateProxyNodesTask.cs index 8fcb57f..8cca644 100644 --- a/src/GenerateProxyNodesTask.cs +++ b/src/Tasks/GenerateProxyNodesTask.cs @@ -4,13 +4,13 @@ using System.IO; using System.Linq; using System.Text; using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -namespace Polonium.Tasks; +using Polonium.Tasks; -public class GenerateProxyNodesTask : Task +// ReSharper disable once CheckNamespace +public class GenerateProxyNodesTask : PoloniumTask { [Required] public string SourceDirectory { get; set; } @@ -97,19 +97,6 @@ public class GenerateProxyNodesTask : Task } } - private string GetDisplayName(ClassDeclarationSyntax cls) - { - string name = cls.Identifier.Text; - SyntaxNode node = cls.Parent; - while (node is not null) - { - if(node is NamespaceDeclarationSyntax ns) - name = ns.Name.ToString() + "." + name; - else if (node is FileScopedNamespaceDeclarationSyntax fs) - name = fs.Name.ToString() + "." + name; - node = node.Parent; - } - return name; - } + } \ No newline at end of file diff --git a/src/Tasks/GenerateRegistryPassThrough.cs b/src/Tasks/GenerateRegistryPassThrough.cs new file mode 100644 index 0000000..50eedcc --- /dev/null +++ b/src/Tasks/GenerateRegistryPassThrough.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Microsoft.Build.Framework; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Polonium.Tasks; + + +// ReSharper disable once CheckNamespace +public class GenerateRegistryPassThrough : PoloniumTask +{ + [Required] public string ProjectDir { get; set; } + + public override bool Execute() + { + try + { + StringBuilder sb = new(); + + string csFile = Directory + .GetFiles($"{ProjectDir}src", "PoloniumRegistry.cs", SearchOption.TopDirectoryOnly) + .FirstOrDefault(); + string code = File.ReadAllText(csFile!); + sb.AppendLine("#pragma warning disable IDE0130"); + foreach (string use in GetUsings(code)) + sb.AppendLine(use); + sb + .AppendLine("// ReSharper disable once CheckNamespace") + .AppendLine("public static partial class GlobalRegistry") + .AppendLine("{"); + + SyntaxTree tree = CSharpSyntaxTree.ParseText(code); + CompilationUnitSyntax root = tree.GetCompilationUnitRoot(); + ClassDeclarationSyntax clas = root + .DescendantNodes() + .OfType() + .FirstOrDefault(cls => cls.Identifier.Text == "PoloniumRegistry"); + IEnumerable properties = clas!.Members + .OfType() + .Where(m => m.AttributeLists + .SelectMany(a => a.Attributes) + .Any(a => a.Name.ToString() == "RegistryPassThrough")); + foreach (PropertyDeclarationSyntax property in properties) + { + if (HasGetterOnly(property)) + sb.AppendLine($" public static {GetDisplayName(property.Type)} {property.Identifier.ToString()} => GlobalRegistry.{property.Identifier.ValueText};"); + else + { + sb + .AppendLine($" public static {GetDisplayName(property.Type)} {property.Identifier.ToString()}") + .AppendLine(" {") + .AppendLine($" get => GlobalRegistry.{property.Identifier.ValueText};") + .AppendLine($" set => GlobalRegistry.{property.Identifier.ValueText} = value;") + .AppendLine(" }"); + } + } + + sb + .AppendLine("}") + .AppendLine("#pragma warning restore IDE0130"); + File.WriteAllText($"{ProjectDir}Package/embedded/Patches/RegistryPassThrough.p.cs", sb.ToString()); + return true; + } + catch (Exception e) + { + Log.LogErrorFromException(e); + return false; + } + } + +} \ No newline at end of file diff --git a/src/GenerateTextureSetTask.cs b/src/Tasks/GenerateTextureSetTask.cs similarity index 89% rename from src/GenerateTextureSetTask.cs rename to src/Tasks/GenerateTextureSetTask.cs index 759029a..1914ff7 100644 --- a/src/GenerateTextureSetTask.cs +++ b/src/Tasks/GenerateTextureSetTask.cs @@ -2,11 +2,11 @@ using System; using System.IO; using System.Text; using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; +using Polonium.Tasks; -namespace Polonium.Tasks; -public class GenerateTextureSetTask : Task +// ReSharper disable once CheckNamespace +public class GenerateTextureSetTask : PoloniumTask { [Required] public string RootPath { get; set; } @@ -103,11 +103,6 @@ public class GenerateTextureSetTask : Task } } - private string GetRelativePath(string basePath, string fullPath) - { - Uri baseUri = new Uri(basePath.EndsWith(Path.DirectorySeparatorChar.ToString()) ? basePath : basePath + Path.DirectorySeparatorChar); - Uri fullUri = new Uri(fullPath); - return Uri.UnescapeDataString(baseUri.MakeRelativeUri(fullUri).ToString().Replace('/', Path.DirectorySeparatorChar)); - } + } \ No newline at end of file