Skip to content

Commit

Permalink
Refactored Scriban templates
Browse files Browse the repository at this point in the history
 - Removed Scriban template abstracts into separate library
 - Referenced new Scriban library
  • Loading branch information
tbm0115 committed Jun 19, 2023
1 parent 10cf69e commit 5ed1eb4
Show file tree
Hide file tree
Showing 16 changed files with 20 additions and 568 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using MtconnectTranspiler.Sinks.CSharp.Attributes;
using MtconnectTranspiler.Sinks.CSharp.Models;
using MtconnectTranspiler.Sinks.CSharp.Models;
using MtconnectTranspiler.Sinks.ScribanTemplates;
using MtconnectTranspiler.Xmi;
using MtconnectTranspiler.Xmi.UML;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using MtconnectTranspiler.Sinks.CSharp.Attributes;
using MtconnectTranspiler.Sinks.ScribanTemplates;
using MtconnectTranspiler.Xmi;
using MtconnectTranspiler.Xmi.UML;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

<ItemGroup>
<PackageReference Include="Consoul" Version="1.6.3" />
<PackageReference Include="MtconnectTranspiler" Version="1.0.6" />
<PackageReference Include="MtconnectTranspiler" Version="1.0.7" />
</ItemGroup>

<ItemGroup>
Expand Down
3 changes: 2 additions & 1 deletion MtconnectTranspiler.Sinks.CSharp.Example/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using ConsoulLibrary;
using Microsoft.Extensions.Logging;
using MtconnectTranspiler;
using MtconnectTranspiler.Sinks;
using MtconnectTranspiler.Sinks.CSharp.Example;

internal class Program
Expand All @@ -18,7 +19,7 @@ private static void Main(string[] args)

var logFactory = LoggerFactory.Create((o) => o.AddConsoulLogger());
var dispatchLogger = logFactory.CreateLogger<TranspilerDispatcher>();
var transpilerLogger = logFactory.CreateLogger<Transpiler>();
var transpilerLogger = logFactory.CreateLogger<ITranspilerSink>();


// NOTE: The GitHubRelease can be a reference to a specific tag referring to the version in which to download.
Expand Down
2 changes: 1 addition & 1 deletion MtconnectTranspiler.Sinks.CSharp.Example/Transpiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ internal class Transpiler : CsharpTranspiler
///
/// </summary>
/// <param name="projectPath"></param>
public Transpiler(string projectPath, ILogger<Transpiler>? logger = default) : base(projectPath, logger) { }
public Transpiler(string projectPath, ILogger<ITranspilerSink>? logger = default) : base(projectPath, logger) { }

public override void Transpile(XmiDocument model, CancellationToken cancellationToken = default)
{
Expand Down

This file was deleted.

207 changes: 5 additions & 202 deletions MtconnectTranspiler.Sinks.CSharp/CsharpTranspiler.cs
Original file line number Diff line number Diff line change
@@ -1,215 +1,18 @@
using MtconnectTranspiler.Sinks.CSharp.Attributes;
using MtconnectTranspiler.Sinks.CSharp.Models;
using Scriban;
using Scriban.Runtime;
using System.Collections.Generic;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using Microsoft.Extensions.Logging;
using MtconnectTranspiler.Xmi;
using Microsoft.Extensions.Logging;
using MtconnectTranspiler.Sinks.ScribanTemplates;

namespace MtconnectTranspiler.Sinks.CSharp
{
/// <summary>
/// A base class for transpiling the MTConnect Standard SysML model into C# files.
/// </summary>
public abstract class CsharpTranspiler : ITranspilerSink
public abstract class CsharpTranspiler : ScribanTranspiler
{
/// <inheritdoc cref="ILogger"/>
protected ILogger<ITranspilerSink> _logger;

/// <summary>
/// The root output directory for the transpiled code.
/// </summary>
public string ProjectPath { get; set; }

private string _templatesPath { get; set; }
/// <summary>
/// Reference to the directory containing all Scriban template files.
/// </summary>
public string TemplatesPath
{
get
{
if (string.IsNullOrEmpty(_templatesPath))
{
_templatesPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Templates");
}
return _templatesPath;
}
set
{
_templatesPath = value;
(TemplateContext.TemplateLoader as IncludeSharedTemplates).TemplatesPath = value;
}
}

/// <summary>
/// Reference to the template rendering context.
/// </summary>
protected TemplateContext TemplateContext { get; set; }

/// <summary>
/// Reference to the core template rendering model.
/// </summary>
protected ScriptObject Model { get; set; }

/// <summary>
/// Constructs a new instance of the transpiler that can transpile the model into C# files.
/// </summary>
/// <param name="projectPath"><inheritdoc cref="ProjectPath" path="/summary"/></param>
/// <param name="projectPath"><inheritdoc cref="ScribanTranspiler.ProjectPath" path="/summary"/></param>
/// <param name="logger"><inheritdoc cref="ILogger"/></param>
public CsharpTranspiler(string projectPath, ILogger<ITranspilerSink> logger = default)
{
ProjectPath = projectPath;
_logger = logger;

TemplateContext = new TemplateContext
{
TemplateLoader = new IncludeSharedTemplates()
};

var helperFunctions = new ScribanHelperMethods();
TemplateContext.PushGlobal(helperFunctions);

var mtconnectFunctions = new MTConnectHelperMethods();
TemplateContext.PushGlobal(mtconnectFunctions);


Model = new ScriptObject();
Model.SetValue("version", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version?.ToString(), true);
TemplateContext.PushGlobal(Model);
}

/// <summary>
/// <inheritdoc cref="ITranspilerSink.Transpile(XmiDocument, CancellationToken)" path="/summary"/>
/// </summary>
/// <param name="model"><inheritdoc cref="XmiDocument" path="/summary"/></param>
/// <param name="cancellationToken"><inheritdoc cref="CancellationToken" path="/summary"/></param>
public abstract void Transpile(XmiDocument model, CancellationToken cancellationToken = default);

/// <summary>
/// An internal cache of <see cref="Template"/>s based on the source <c>.scriban</c> file location.
/// </summary>
protected Dictionary<string, Template> templateCache = new Dictionary<string, Template>();
/// <summary>
/// Retrieves a <see cref="Template"/> from a <c>.scriban</c> file at the given <paramref name="filepath"/>.
/// </summary>
/// <param name="filepath">Location of the <c>.scriban</c> file to parse a <see cref="Template"/>.</param>
/// <returns>Reference to the <see cref="Template"/> parsed from the given <c>.scriban</c> at the <paramref name="filepath"/>.</returns>
/// <exception cref="InvalidOperationException"></exception>
protected Template GetTemplate(string filepath)
{
if (templateCache.TryGetValue(filepath, out Template template)) return template;

if (!File.Exists(filepath)) throw new FileNotFoundException("Could not find template file", filepath);

string templateContent = File.ReadAllText(filepath);
template = Template.Parse(templateContent);

if (template != null)
{
if (templateCache.ContainsKey(filepath)) return templateCache[filepath];
_logger?.LogInformation("Registering Template from file: {Filepath}", filepath);
templateCache.Add(filepath, template);
return template;
}

throw new InvalidOperationException();
}

/// <summary>
/// Renders the <paramref name="template"/> into C#.
/// </summary>
/// <param name="member">The member name used in the <paramref name="template"/> for the provided <paramref name="value"/>.</param>
/// <param name="value">The value for the provided <paramref name="member"/> reference.</param>
/// <param name="template">The <see cref="Template"/> to render C#.</param>
/// <returns>Raw C# code.</returns>
protected string RenderTemplateWithModel(string member, object value, Template template)
{
if (value == null) return String.Empty;
if (Model.Contains(member))
{
Model.Remove(member);
}
Model.SetValue(member, value, true);
string csharp = template.Render(TemplateContext);

Model.Remove(member);

return csharp;
}

/// <summary>
/// Processes a collection of objects, decorated with the <see cref="ScribanTemplateAttribute"/>, into a C# file.
/// </summary>
/// <typeparam name="T">An implementation of <see cref="IFileSource"/>.</typeparam>
/// <param name="items">Collection of objects, decorated with <see cref="ScribanTemplateAttribute"/>.</param>
/// <param name="folderPath">Location to save the <c>.cs</c> files.</param>
/// <param name="overwriteExisting">Flag for whether or not the output file should be overwritten</param>
protected void ProcessTemplate<T>(IEnumerable<T> items, string folderPath, bool overwriteExisting = false) where T : IFileSource
{
if (items == null || items.Any() == false) return;

foreach (var item in items) ProcessTemplate(item, folderPath, overwriteExisting);
}
/// <summary>
/// Processes an object, decorated with the <see cref="ScribanTemplateAttribute"/>, into a C# file.
/// </summary>
/// <typeparam name="T">An implementation of <see cref="IFileSource"/>.</typeparam>
/// <param name="item">An object, decorated with <see cref="ScribanTemplateAttribute"/>.</param>
/// <param name="folderPath">Location to save the <c>.cs</c> file.</param>
/// <param name="overwriteExisting">Flag for whether or not the output file should be overwritten</param>
/// <exception cref="NotImplementedException"></exception>
/// <exception cref="FileNotFoundException"></exception>
protected void ProcessTemplate<T>(T item, string folderPath, bool overwriteExisting = false) where T : IFileSource
{
if (item == null) return;

System.Type type = typeof(T);

ScribanTemplateAttribute attr = type.GetCustomAttribute<ScribanTemplateAttribute>()
?? throw new NotImplementedException("The type of " + typeof(T).Name + " must be decorated with the ScribanTemplateAttribute");

Template template = GetTemplate(Path.Combine(TemplatesPath, attr.Filename));
if (template == null)
{
var templateNotFound = new FileNotFoundException();
_logger?.LogError(templateNotFound, "Could not find template");
throw templateNotFound;
}

string filepath = Path.Combine(folderPath, item.Filename);

string csharp;
try
{
csharp = RenderTemplateWithModel("source", item, template);
}
catch (Exception ex)
{
_logger?.LogError(ex, "Failed to render C#");
throw ex;
}

if (!string.IsNullOrEmpty(csharp))
{
try
{
XmiTranspilerExtensions.WriteToFile(filepath, csharp, overwriteExisting);
}
catch (Exception ex)
{
_logger?.LogError(ex, "Failed to write to file: {Filepath}", filepath);
throw ex;
}
} else
{
_logger?.LogWarning("Cannot write an empty C# file: {Filepath}", filepath);
}
}
public CsharpTranspiler(string projectPath, ILogger<ITranspilerSink> logger = default) : base(projectPath, logger) { }
}
}
49 changes: 0 additions & 49 deletions MtconnectTranspiler.Sinks.CSharp/IncludeSharedTemplates.cs

This file was deleted.

2 changes: 1 addition & 1 deletion MtconnectTranspiler.Sinks.CSharp/Models/Class.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using MtconnectTranspiler.Sinks.CSharp.Attributes;
using MtconnectTranspiler.Sinks.ScribanTemplates;
using MtconnectTranspiler.Xmi;
using MtconnectTranspiler.Xmi.UML;
using System.Collections.Generic;
Expand Down
2 changes: 1 addition & 1 deletion MtconnectTranspiler.Sinks.CSharp/Models/Enum.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using MtconnectTranspiler.Sinks.CSharp.Attributes;
using MtconnectTranspiler.Sinks.ScribanTemplates;
using MtconnectTranspiler.Xmi;
using MtconnectTranspiler.Xmi.UML;
using System.Collections.Generic;
Expand Down
20 changes: 0 additions & 20 deletions MtconnectTranspiler.Sinks.CSharp/Models/IFileSource.cs

This file was deleted.

Loading

0 comments on commit 5ed1eb4

Please sign in to comment.