forked from daveaglick/Scripty
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathScriptEngine.cs
More file actions
150 lines (133 loc) · 5.64 KB
/
ScriptEngine.cs
File metadata and controls
150 lines (133 loc) · 5.64 KB
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Formatting;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Scripting;
using Scripty.Core.ProjectTree;
namespace Scripty.Core
{
using System.Collections;
using System.Reflection;
using Output;
using Resolvers;
public class ScriptEngine
{
private readonly string _projectFilePath;
public ScriptEngine(string projectFilePath)
: this(projectFilePath, null, null)
{
}
public ScriptEngine(string projectFilePath, string solutionFilePath, IReadOnlyDictionary<string, string> properties)
{
if (string.IsNullOrEmpty(projectFilePath))
{
throw new ArgumentException("Value cannot be null or empty.", nameof(projectFilePath));
}
if (!Path.IsPathRooted(projectFilePath))
{
throw new ArgumentException("Project path must be absolute", nameof(projectFilePath));
}
// The solution path is optional. If it's provided, the solution will be loaded and
// the project found in the solution. If not, then the project is loaded directly.
if (solutionFilePath != null)
{
if (!Path.IsPathRooted(solutionFilePath))
{
throw new ArgumentException("Solution path must be absolute", nameof(solutionFilePath));
}
}
_projectFilePath = projectFilePath;
ProjectRoot = new ProjectRoot(projectFilePath, solutionFilePath, properties);
}
public ProjectRoot ProjectRoot { get; }
public async Task<ScriptResult> Evaluate(ScriptSource source)
{
var resolver = new InterceptDirectiveResolver();
var assembliesToRef = new List<Assembly>
{
typeof(object).Assembly, //mscorlib
typeof(Microsoft.CodeAnalysis.Project).Assembly, // Microsoft.CodeAnalysis.Workspaces
typeof(Microsoft.Build.Evaluation.Project).Assembly, // Microsoft.Build
typeof(ScriptEngine).Assembly // Scripty.Core
};
var namepspaces = new List<string>
{
"System",
"Scripty.Core",
"Scripty.Core.Output",
"Scripty.Core.ProjectTree"
};
var options = ScriptOptions.Default
.WithFilePath(source.FilePath)
.WithReferences(assembliesToRef)
.WithImports(namepspaces)
.WithSourceResolver(resolver);
using (ScriptContext context = GetContext(source.FilePath))
{
try
{
await CSharpScript.EvaluateAsync(source.Code, options, context);
foreach (var outputFile in context.Output.OutputFiles)
{
(outputFile as OutputFile).Close();
if (outputFile.FormatterEnabled)
{
var document = ProjectRoot.Analysis.AddDocument(outputFile.FilePath, File.ReadAllText(outputFile.FilePath));
var resultDocument = await Formatter.FormatAsync(
document,
outputFile.FormatterOptions.Apply(ProjectRoot.Workspace.Options)
);
var resultContent = await resultDocument.GetTextAsync();
File.WriteAllText(outputFile.FilePath, resultContent.ToString());
}
}
}
catch (CompilationErrorException compilationError)
{
return new ScriptResult(context.Output.OutputFiles,
compilationError.Diagnostics
.Select(x => new ScriptError
{
Message = x.GetMessage(),
Line = x.Location.GetLineSpan().StartLinePosition.Line,
Column = x.Location.GetLineSpan().StartLinePosition.Character
})
.ToList());
}
catch (AggregateException aggregateException)
{
return new ScriptResult(context.Output.OutputFiles,
aggregateException.InnerExceptions
.Select(x => new ScriptError
{
Message = x.ToString()
}).ToList());
}
catch (Exception ex)
{
return new ScriptResult(context.Output.OutputFiles,
new[]
{
new ScriptError
{
Message = ex.ToString()
}
});
}
return new ScriptResult(context.Output.OutputFiles);
}
}
private ScriptContext GetContext(string scriptFilePath)
{
if (scriptFilePath == null)
{
throw new ArgumentNullException(nameof(scriptFilePath));
}
return new ScriptContext(scriptFilePath, _projectFilePath, ProjectRoot);
}
}
}