-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCodeTransformer.cs
More file actions
100 lines (88 loc) · 4.04 KB
/
Copy pathCodeTransformer.cs
File metadata and controls
100 lines (88 loc) · 4.04 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
using System.IO;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
namespace NETMetaCoder
{
/// <summary>
/// This class provides the core functionality of the library.
///
/// It's focal point is method <see cref="Wrap"/> which is responsible for running the code wrapping logic for a
/// compilation unit.
/// </summary>
/// <seealso cref="CodeWrapTransformationOptions"/>
/// <seealso cref="SyntaxScanner"/>
/// <seealso cref="SyntaxRewriter"/>
public sealed class CodeTransformer
{
private CodeWrapTransformationOptions _options;
private readonly bool _writeOutput;
/// <summary>
/// Creates a new <see cref="CodeTransformer"/> instance.
/// </summary>
/// <param name="options"></param>
/// <param name="writeOutput"></param>
/// <seealso cref="CodeWrapTransformationOptions"/>
public CodeTransformer(CodeWrapTransformationOptions options, bool writeOutput = true)
{
_options = options;
_writeOutput = writeOutput;
if (Directory.Exists(_options.OutputDirectory))
{
Directory.Delete(_options.OutputDirectory, true);
}
}
/// <summary>
/// This function receives a file path and potentially produces a code syntax transformation of that file's
/// code.
/// </summary>
/// <param name="filePath"></param>
/// <remarks>
/// This method takes the following steps:
/// 1. Is parses its syntax tree.
/// 2. It scans the parsed syntax tree into a <see cref="SyntaxEnvelope"/>, keeping only the parts relevant to
/// the functionality of this library.
/// 3. If the file needs to be rewritten, then the original file is changed so that its code can be wrapped and
/// companion file with the wrapping code is created.
/// </remarks>
/// <seealso cref="SyntaxScanner"/>
/// <seealso cref="SyntaxRewriter"/>
public CodeTransformationResult Wrap(string filePath)
{
var relativeFilePath = PathHelper.GetRelativePath(_options.FileBasePath, filePath);
var code = File.ReadAllText(filePath);
var syntaxTree = CSharpSyntaxTree.ParseText(code);
var syntaxScan = SyntaxScanner.ScanSyntaxTree(syntaxTree, _options.AttributeNames);
var rewrittenSyntax = SyntaxRewriter.RewriteSyntaxTree(syntaxTree, _options.AttributeNames, syntaxScan);
var mirrorFilePath = Path.Combine(_options.OutputDirectory, relativeFilePath);
// ReSharper disable once AssignNullToNotNullAttribute
var companionFilePath = Path.Combine(
Path.GetDirectoryName(mirrorFilePath),
Path.GetFileNameWithoutExtension(mirrorFilePath) +
".Companion" +
Path.GetExtension(mirrorFilePath));
if (rewrittenSyntax.HasChanges)
{
var rewrittenSyntaxCode = rewrittenSyntax.SyntaxTree.GetRoot().ToFullString();
if (_writeOutput)
{
Directory.CreateDirectory(Path.GetDirectoryName(mirrorFilePath) ??
throw new DirectoryNotFoundException($"The directory of {mirrorFilePath} does not exist."));
File.WriteAllText(mirrorFilePath, rewrittenSyntaxCode);
}
var builtSyntax = new SyntaxBuilder(syntaxScan, ref _options).Build();
var newCode = builtSyntax.GetRoot().NormalizeWhitespace(eol: _options.EndOfLine).ToFullString() +
_options.EndOfLine;
if (_writeOutput)
{
File.WriteAllText(companionFilePath, newCode);
}
}
return new CodeTransformationResult
{
TransformationOccured = rewrittenSyntax.HasChanges,
MirrorFilePath = mirrorFilePath,
CompanionFilePath = companionFilePath
};
}
}
}