Last active
June 30, 2019 11:36
-
-
Save deanebarker/3e0d7bc2cbcbc02bf5372ef6ec75fb18 to your computer and use it in GitHub Desktop.
A Scriban module for Wyam
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Scriban; | |
using Scriban.Parsing; | |
using Scriban.Runtime; | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using Wyam.Common.Configuration; | |
using Wyam.Common.Documents; | |
using Wyam.Common.Execution; | |
using Wyam.Common.Modules; | |
namespace Wyam.Scriban | |
{ | |
/* | |
Usage: | |
new ScribanModule("my_template.tpl", d => { return d; }) | |
.WithData("name", "Deane") | |
.WithFunction("rapperize", new Func<string, string>(s => s + ", yo.")) | |
.WithType("functions", typeofOf(MyTypeWithABunchOfStaticMethods)) | |
.WithDocKey("what_my_doc_variable_should_be_called") // defaults to "doc" | |
.WithSettingsKey("what_the_engine_settings_should_be_called") // defaults to "settings" | |
.WithLayout("a_template_to_add_to_the_end.tpl") | |
.WithScriptObject(myCustomScriptObject) | |
*/ | |
public class RenderScriban : IModule | |
{ | |
private string _template; | |
private string _templateFile; | |
private string _preTemplate; | |
private string _preTemplateFile; | |
private string _postTemplate; | |
private string _postTemplateFile; | |
private DocumentConfig _modelFactory; | |
private string _layout; | |
private string _settingsKey = "settings"; | |
private string _docKey = "doc"; | |
private Dictionary<string, object> _data = new Dictionary<string, object>(); | |
private Dictionary<string, Delegate> _functions = new Dictionary<string, Delegate>(); | |
private List<Type> _types = new List<Type>(); | |
private List<ScriptObject> _scriptObjects = new List<ScriptObject>(); | |
public RenderScriban(DocumentConfig modelFactory) | |
{ | |
_modelFactory = modelFactory; | |
} | |
public RenderScriban WithTemplate(string template) | |
{ | |
_template = template; | |
return this; | |
} | |
public RenderScriban WithTemplateFile(string templateFile) | |
{ | |
_templateFile = templateFile; | |
return this; | |
} | |
public RenderScriban WithPreTemplate(string preTemplate) | |
{ | |
_preTemplate = preTemplate; | |
return this; | |
} | |
public RenderScriban WithPreTemplateFile(string preTemplateFile) | |
{ | |
_preTemplateFile = preTemplateFile; | |
return this; | |
} | |
public RenderScriban WithPostTemplate(string postTemplate) | |
{ | |
_postTemplate = postTemplate; | |
return this; | |
} | |
public RenderScriban WithPostTemplateFile(string postTemplateFile) | |
{ | |
_postTemplateFile = postTemplateFile; | |
return this; | |
} | |
public RenderScriban WithData(string key, object value) | |
{ | |
_data.Add(key, value); | |
return this; | |
} | |
public RenderScriban WithFunction(string key, Delegate value) | |
{ | |
_functions.Add(key, value); | |
return this; | |
} | |
public RenderScriban WithLayout(string layout) | |
{ | |
_layout = layout; | |
return this; | |
} | |
public RenderScriban WithType(Type type) | |
{ | |
_types.Add(type); | |
return this; | |
} | |
public RenderScriban WithSettingsKey(string key) | |
{ | |
_settingsKey = key; | |
return this; | |
} | |
public RenderScriban WithDocKey(string key) | |
{ | |
_docKey = key; | |
return this; | |
} | |
public RenderScriban WithScriptObject(ScriptObject obj) | |
{ | |
_scriptObjects.Add(obj); | |
return this; | |
} | |
public IEnumerable<IDocument> Execute(IReadOnlyList<IDocument> inputs, IExecutionContext context) | |
{ | |
var templateString = new StringBuilder(); | |
if (_preTemplate != null) | |
{ | |
templateString.Append(_preTemplate); | |
} | |
if (_preTemplateFile != null) | |
{ | |
templateString.Append(context.FileSystem.GetInputFile(_preTemplateFile).ReadAllText()); | |
} | |
if(_template != null) | |
{ | |
templateString.Append(_template); | |
} | |
if(_templateFile != null) | |
{ | |
templateString.Append(context.FileSystem.GetInputFile(_templateFile).ReadAllText()); | |
} | |
if (_postTemplate != null) | |
{ | |
templateString.Append(_postTemplate); | |
} | |
if (_postTemplateFile != null) | |
{ | |
templateString.Append(context.FileSystem.GetInputFile(_postTemplateFile).ReadAllText()); | |
} | |
var template = Template.Parse(templateString.ToString()); | |
// This cannot be parallel because Scriban TemplateContext is NOT thread-safe | |
return inputs.AsParallel().Select(context, input => | |
{ | |
// Load the main doc and the global settings | |
var templateVars = new ScriptObject | |
{ | |
{ _docKey, _modelFactory(input, context) }, | |
{ _settingsKey, context.Settings } | |
}; | |
// Load the data that was passed in | |
foreach (var pair in _data) | |
{ | |
templateVars.Add(pair.Key, pair.Value); | |
} | |
// Load the custom functions | |
foreach (var pair in _functions) | |
{ | |
templateVars.Import(pair.Key, pair.Value); | |
} | |
// Load the types | |
foreach (var type in _types) | |
{ | |
templateVars.Import(type); | |
} | |
// Load a context, with a template loader that will work off the Wyam file system | |
var templateContext = new TemplateContext | |
{ | |
TemplateLoader = new TemplateLoader(context) | |
}; | |
templateContext.PushGlobal(templateVars); | |
// Load the script objects | |
foreach(var obj in _scriptObjects) | |
{ | |
templateContext.PushGlobal(obj); | |
} | |
// Execute | |
var result = template.Render(templateContext); | |
// Return a new doc | |
var x = context.GetDocument(input, GenerateStreamFromString(result)); | |
return x; | |
}); | |
} | |
public static Stream GenerateStreamFromString(string s) | |
{ | |
var stream = new MemoryStream(); | |
var writer = new StreamWriter(stream); | |
writer.Write(s); | |
writer.Flush(); | |
stream.Position = 0; | |
return stream; | |
} | |
} | |
public class TemplateLoader : ITemplateLoader | |
{ | |
private IExecutionContext _wyamContext; | |
public TemplateLoader(IExecutionContext wyamContext) | |
{ | |
_wyamContext = wyamContext; | |
} | |
public string GetPath(TemplateContext context, Scriban.Parsing.SourceSpan callerSpan, string templateName) | |
{ | |
return _wyamContext.FileSystem.GetInputFile(templateName).Path.FullPath; | |
} | |
public string Load(TemplateContext context, Scriban.Parsing.SourceSpan callerSpan, string templatePath) | |
{ | |
return _wyamContext.FileSystem.GetFile(templatePath).ReadAllText(); | |
} | |
public ValueTask<string> LoadAsync(TemplateContext context, Scriban.Parsing.SourceSpan callerSpan, string templatePath) | |
{ | |
throw new NotImplementedException(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment