using System.Reflection; using InterfaceForward.Application.Contracts.ForwardCore; using Microsoft.CodeAnalysis; namespace InterfaceForward.Application.ForwardCore; internal static class NatashaScriptCompiler { public static Action CompileAction(string script) { var method = Compile(script, "void"); return method.CreateDelegate>(); } public static Func CompileAsyncFunc(string script) { var method = Compile(script, "async System.Threading.Tasks.Task"); return method.CreateDelegate>(); } static MethodInfo Compile(string script, string returnType) { var typeName = "Script_" + Guid.NewGuid().ToString("N"); var code = $$""" using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using InterfaceForward.Application.Contracts.ForwardCore; using InterfaceForward.Domain.Shared; using InterfaceForward.Domain.Shared.Dtos; using InterfaceForward.Domain.Shared.Enum; using Newtonsoft.Json.Linq; public static class {{typeName}} { public static {{returnType}} Run(ForwardCoreContext obj) { var context = obj; {{script}} } } """; var assembly = new AssemblyCSharpBuilder() .UseRandomDomain() .WithSpecifiedReferences(GetMetadataReferences()) .Add(code) .GetAssembly(); return assembly .GetType(typeName, throwOnError: true)! .GetMethod("Run", BindingFlags.Public | BindingFlags.Static)!; } static IEnumerable GetMetadataReferences() { var paths = new HashSet(StringComparer.OrdinalIgnoreCase); if (AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES") is string trustedPlatformAssemblies) { foreach (var path in trustedPlatformAssemblies.Split(Path.PathSeparator)) { AddPath(path); } } foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { AddPath(assembly.Location); } return paths.Select(path => MetadataReference.CreateFromFile(path)); void AddPath(string? path) { if (!string.IsNullOrWhiteSpace(path) && File.Exists(path)) { paths.Add(path); } } } }