File size: 4,759 Bytes
1ae2e8e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace RobloxCS
{
    public static class TranspilerUtility
    {
        public static RojoProject? GetRojoProject(string inputDirectory, string projectName)
        {
            if (projectName == "UNIT_TESTING") return null;

            var path = RojoReader.FindProjectPath(inputDirectory, projectName);
            if (path == null)
            {
                Logger.Error($"Failed to find Rojo project file \"{projectName}.project.json\"!");
                return null!;
            }

            return RojoReader.Read(path);
        }

        public static string CleanUpLuaForTests(string luaSource, int? extraLines)
        {
            var lines = luaSource.Split('\n').ToList();
            lines.RemoveRange(0, 2 + (extraLines ?? 0));

            return string.Join('\n', lines).Replace("\r", "").Trim();
        }

        public static string GenerateLua(
            SyntaxTree tree,
            CSharpCompilation compiler,
            MemberCollectionResult members,
            string inputDirectory = "",
            ConfigData? config = null
        )
        {
            config ??= ConfigReader.UnitTestingConfig;
            var rojoProject = GetRojoProject(inputDirectory, config.RojoProjectName);
            var codeGenerator = new CodeGenerator(tree, compiler, rojoProject, members, config, Utility.FixPathSep(inputDirectory));
            return codeGenerator.GenerateLua();
        }

        public static CSharpCompilation GetCompiler(List<SyntaxTree> trees, ConfigData? config = null)
        {
            config ??= ConfigReader.UnitTestingConfig;
            var compilationOptions = new CSharpCompilationOptions(OutputKind.ConsoleApplication);
            var compiler = CSharpCompilation.Create(
                assemblyName: config.CSharpOptions.AssemblyName,
                syntaxTrees: trees,
                references: GetCompilationReferences(),
                options: compilationOptions
            );

            return compiler;
        }

        public static SyntaxTree TransformTree(SyntaxTree cleanTree, HashSet<Func<SyntaxTree, ConfigData, SyntaxTree>> transformMethods, ConfigData? config = null)
        {
            config ??= ConfigReader.UnitTestingConfig;

            var tree = cleanTree;
            foreach (var transform in transformMethods)
            {
                tree = transform(tree, config);
            }
            return tree;
        }

        public static SyntaxTree ParseTree(string source, string sourceFile = "TestFile.client.cs")
        {
            var cleanTree = CSharpSyntaxTree.ParseText(source);
            var compilationUnit = (CompilationUnitSyntax)cleanTree.GetRoot();
            var usingDirective = SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("System"));
            var newRoot = compilationUnit.AddUsings(usingDirective);
            return cleanTree
                .WithRootAndOptions(newRoot, cleanTree.Options)
                .WithFilePath(sourceFile);
        }

        private static List<PortableExecutableReference> GetCompilationReferences()
        {
            var runtimeLibAssemblyPath = string.Join('/', Utility.GetAssemblyDirectory(), Utility.RuntimeAssemblyName + ".dll");
            if (!File.Exists(runtimeLibAssemblyPath))
            {
                var directoryName = Path.GetDirectoryName(runtimeLibAssemblyPath);
                Logger.Error($"Failed to find {Utility.RuntimeAssemblyName}.dll in {(directoryName == null ? "(could not find assembly directory)" : Utility.FixPathSep(directoryName))}");
            }

            var references = new List<PortableExecutableReference>()
            {
                MetadataReference.CreateFromFile(runtimeLibAssemblyPath)
            };

            foreach (var coreLibReference in GetCoreLibReferences())
            {
                references.Add(coreLibReference);
            }
            return references;
        }

        private static HashSet<PortableExecutableReference> GetCoreLibReferences()
        {
            var coreLib = typeof(object).GetTypeInfo().Assembly.Location;
            HashSet<string> coreDlls = ["System.Runtime.dll", "System.Core.dll", "System.Collections.dll"];
            HashSet<PortableExecutableReference> references = [MetadataReference.CreateFromFile(coreLib)];
            
            foreach (var coreDll in coreDlls)
            {
                var dllPath = Path.Combine(Path.GetDirectoryName(coreLib)!, coreDll);
                references.Add(MetadataReference.CreateFromFile(dllPath));
            }
            return references;
        }
    }
}