using System.IO;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
namespace NETMetaCoder
{
///
/// This class provides the core functionality of the library.
///
/// It's focal point is method which is responsible for running the code wrapping logic for a
/// compilation unit.
///
///
///
///
public sealed class CodeTransformer
{
private CodeWrapTransformationOptions _options;
private readonly bool _writeOutput;
///
/// Creates a new instance.
///
///
///
///
public CodeTransformer(CodeWrapTransformationOptions options, bool writeOutput = true)
{
_options = options;
_writeOutput = writeOutput;
if (Directory.Exists(_options.OutputDirectory))
{
Directory.Delete(_options.OutputDirectory, true);
}
}
///
/// This function receives a file path and potentially produces a code syntax transformation of that file's
/// code.
///
///
///
/// This method takes the following steps:
/// 1. Is parses its syntax tree.
/// 2. It scans the parsed syntax tree into a , 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.
///
///
///
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
};
}
}
}