Skip to content

Commit

Permalink
Reworked code gen server interaction
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelstaib committed Feb 24, 2022
1 parent 708437d commit bdbbf8e
Show file tree
Hide file tree
Showing 12 changed files with 569 additions and 146 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace StrawberryShake.CodeGeneration.CSharp;

public static class GeneratorSink
{
public static string Location => Path.Combine(Path.GetTempPath(), "__berry");

public static string ErrorLogFileName => Path.Combine(Location, "errors.log");

public static string CreateFileName() => Path.Combine(Location, Path.GetRandomFileName());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace StrawberryShake.CodeGeneration.CSharp;

internal static class Names
{
public const string GeneratorRequest = nameof(GeneratorRequest);
public const string DocumentFileName = nameof(DocumentFileName);
public const string ConfigFileName = "configFileName";
public const string RootDirectory = "rootDirectory";
public const string DefaultNamespace = "defaultNamespace";
public const string PersistedQueryDirectory = "persistedQueryDirectory";
public const string Option = "option";
public const string ErrorLocation = "Location";
public const string Line = "line";
public const string Column = "column";
public const string Error = nameof(Error);
public const string Code = "code";
public const string FilePath = "filePath";
public const string Title = "title";
public const string Message = nameof(Message);
public const string Document = nameof(Document);
public const string Hash = "hash";
public const string Path = "path";
public const string Name = "name";
public const string SourceText = nameof(SourceText);
public const string Kind = "kind";
public const string GeneratorResponse = nameof(GeneratorResponse);
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,84 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Runtime.Serialization;
using System.Xml.Linq;
using static System.Enum;
using static StrawberryShake.CodeGeneration.CSharp.Names;
using static StrawberryShake.CodeGeneration.CSharp.RequestOptions;

namespace StrawberryShake.CodeGeneration.CSharp;

public static class RequestFormatter
{
private static readonly JsonSerializerOptions _options = new()
{
Converters = { new JsonStringEnumConverter() },
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};

public static string Format(GeneratorRequest request)
{
var temp = Path.Combine(Path.GetTempPath(), "__berry");
var temp = GeneratorSink.Location;

if (!Directory.Exists(temp))
{
Directory.CreateDirectory(temp);
}

var fileName = Path.Combine(temp, Path.GetRandomFileName());
var buffer = JsonSerializer.SerializeToUtf8Bytes(request, _options);
File.WriteAllBytes(fileName, buffer);
var fileName = GeneratorSink.CreateFileName();

var root = new XElement(Names.GeneratorRequest);
root.Add(new XAttribute(ConfigFileName, request.ConfigFileName));
root.Add(new XAttribute(RootDirectory, request.RootDirectory));
root.Add(new XAttribute(DefaultNamespace, request.DefaultNamespace ?? string.Empty));
root.Add(new XAttribute(PersistedQueryDirectory, request.PersistedQueryDirectory ?? string.Empty));
root.Add(new XAttribute(Option, request.Option.ToString()));

foreach (var file in request.DocumentFileNames)
{
root.Add(new XElement(DocumentFileName, file));
}

using FileStream fileStream = File.Create(fileName);
var document = new XDocument();
document.Add(root);
document.Save(fileStream, SaveOptions.None);

return fileName;
}

public static GeneratorRequest Take(string fileName)
{
GeneratorRequest request = Parse(fileName);
File.Delete(fileName);
return request;
}

public static GeneratorRequest Parse(string fileName)
{
using FileStream fileStream = File.OpenRead(fileName);
var document = XDocument.Load(fileStream);

if (document.Root is null || !document.Root.Name.LocalName.Equals(Names.GeneratorRequest))
{
throw new InvalidDataContractException("Missing the request root element.");
}

var configFileName = document.Root.Attribute(ConfigFileName)?.Value ??
throw new InvalidDataContractException("Missing the configFileName attribute.");
var rootDirectory = document.Root.Attribute(RootDirectory)?.Value;
var defaultNamespace = document.Root.Attribute(DefaultNamespace)?.Value;
var persistedQueryDirectory = document.Root.Attribute(PersistedQueryDirectory)?.Value;
var optionString = document.Root.Attribute(Option)?.Value;

var documentFileNames = new List<string>();

foreach (XElement documentFileName in document.Root.Elements(DocumentFileName))
{
if (!string.IsNullOrEmpty(documentFileName.Value))
{
documentFileNames.Add(documentFileName.Value);
}
}

return new GeneratorRequest(
configFileName,
documentFileNames,
string.IsNullOrEmpty(rootDirectory) ? null : rootDirectory,
string.IsNullOrEmpty(defaultNamespace) ? null : defaultNamespace,
string.IsNullOrEmpty(persistedQueryDirectory) ? null : persistedQueryDirectory,
string.IsNullOrEmpty(optionString) ? Default : Parse<RequestOptions>(optionString));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
using System.Runtime.Serialization;
using System.Text.Json;
using System.Xml.Linq;
using static StrawberryShake.CodeGeneration.CSharp.Names;
using Path = System.IO.Path;

namespace StrawberryShake.CodeGeneration.CSharp;

public static class ResponseFormatter
{
public static void Format(GeneratorResponse response, string fileName)
{
if (File.Exists(fileName))
{
File.Delete(fileName);
}

using FileStream fileStream = File.Create(fileName);
var document = new XDocument();
SerializeGeneratorResponse(document, response);
document.Save(fileStream, SaveOptions.None);
}

public static GeneratorResponse Take(string fileName)
{
GeneratorResponse response = Parse(fileName);
File.Delete(fileName);
return response;
}

public static GeneratorResponse Parse(string fileName)
{
using FileStream fileStream = File.OpenRead(fileName);
var document = XDocument.Load(fileStream);
return DeserializeGeneratorResponse(document);
}

private static GeneratorResponse DeserializeGeneratorResponse(XDocument document)
{
if (document.Root is null || !document.Root.Name.LocalName.Equals(Names.GeneratorResponse))
{
throw new InvalidDataContractException("The generator response has an invalid format.");
}

var documents = new List<GeneratorDocument>();
var errors = new List<GeneratorError>();

foreach (XElement documentElement in document.Root.Elements(Document))
{
documents.Add(DeserializeGeneratorDocument(documentElement));
}

foreach (XElement errorElement in document.Root.Elements(Error))
{
errors.Add(DeserializeGeneratorError(errorElement));
}

return new GeneratorResponse(documents, errors);
}

private static void SerializeGeneratorResponse(XDocument parent, GeneratorResponse response)
{
var responseElement = new XElement(Names.GeneratorResponse);

foreach (GeneratorDocument document in response.Documents)
{
SerializeGeneratorDocument(responseElement, document);
}

foreach (GeneratorError error in response.Errors)
{
SerializeGeneratorError(responseElement, error);
}

parent.Add(responseElement);
}

private static GeneratorDocument DeserializeGeneratorDocument(XElement documentElement)
{
XAttribute? nameAttribute = documentElement.Attribute(Name);
XAttribute? kindAttribute = documentElement.Attribute(Kind);
XElement? sourceTextElement = documentElement.Element(SourceText);
XAttribute? hashAttribute = documentElement.Attribute(Hash);
XAttribute? pathAttribute = documentElement.Attribute(Names.Path);

if (nameAttribute is null || kindAttribute is null || sourceTextElement is null)
{
throw new InvalidDataContractException("The document has an invalid format.");
}

return new GeneratorDocument(
nameAttribute.Value,
sourceTextElement.Value,
Enum.Parse<GeneratorDocumentKind>(kindAttribute.Value),
hashAttribute?.Value,
pathAttribute?.Value);
}

private static void SerializeGeneratorDocument(XElement parent, GeneratorDocument document)
{
var documentElement = new XElement(Document);
documentElement.Add(new XAttribute(Name, document.Name));
documentElement.Add(new XAttribute(Kind, document.Kind.ToString()));
documentElement.Add(new XElement(SourceText, document.SourceText));

if (document.Hash is not null)
{
documentElement.Add(new XAttribute(Hash, document.Hash));
}

if (document.Path is not null)
{
documentElement.Add(new XAttribute(Names.Path, document.Path));
}

parent.Add(documentElement);
}

private static GeneratorError DeserializeGeneratorError(XElement errorElement)
{
XAttribute? codeAttribute = errorElement.Attribute(Code);
XAttribute? titleAttribute = errorElement.Attribute(Title);
XAttribute? filePathAttribute = errorElement.Attribute(FilePath);
XElement? messageElement = errorElement.Element(Message);
XElement? locationElement = errorElement.Element(ErrorLocation);

if (messageElement is null || codeAttribute is null || titleAttribute is null)
{
throw new InvalidDataContractException("The error has an invalid format.");
}

Location? location = null;
if (locationElement is not null)
{
location = DeserializeLocation(locationElement);
}

return new GeneratorError(
codeAttribute.Value,
titleAttribute.Value,
messageElement.Value,
filePathAttribute?.Value,
location);
}

private static void SerializeGeneratorError(XElement parent, GeneratorError error)
{
var errorElement = new XElement(Error);
errorElement.Add(new XAttribute(Code, error.Code));
errorElement.Add(new XAttribute(Title, error.Title));

if (!string.IsNullOrEmpty(error.FilePath))
{
errorElement.Add(new XAttribute(FilePath, error.FilePath));
}

errorElement.Add(new XElement(Message, error.Message));

if (error.Location is not null)
{
SerializeLocation(errorElement, error.Location);
}

parent.Add(errorElement);
}

private static Location DeserializeLocation(XElement location)
{
XAttribute? line = location.Attribute(Line);
XAttribute? column = location.Attribute(Column);

return new Location(
line is null ? 0 : int.Parse(line.Value),
column is null ? 0 : int.Parse(column.Value));
}

private static void SerializeLocation(XElement parent, Location location)
{
var locationElement = new XElement(ErrorLocation);
locationElement.Add(new XAttribute(Line, location.Line));
locationElement.Add(new XAttribute(Column, location.Column));
parent.Add(locationElement);
}
}
Loading

0 comments on commit bdbbf8e

Please sign in to comment.