public void TestMustacheTemplateProcessSingleTemplateWithNoScriptShouldWork() { // 1. Prepare template var templateName = "NoScript"; string template = @" {{#model}} name1={{name1}}, name2={{name2}}; {{/model}} "; var model = new { model = new object[] { new { name1 = "test1" }, new { name2 = "test2" }, } }; var modelFileName = Path.Combine(_inputFolder, "TestTemplateProcessor_NoScript.yml"); var item = new InternalManifestItem { DocumentType = string.Empty, Key = modelFileName, FileWithoutExtension = Path.ChangeExtension(modelFileName, null), ResourceFile = modelFileName }; ProcessTemplate(templateName, null, new[] { item }, model, _outputFolder, Tuple.Create("default.tmpl", template)); var outputFile = Path.Combine(_outputFolder, Path.ChangeExtension(modelFileName, string.Empty)); Assert.True(File.Exists(outputFile)); Assert.Equal(@" name1=test1, name2=; name1=, name2=test2; ", File.ReadAllText(outputFile)); }
public void JsCreateDateShouldNotThrowError() { var templateName = "TemplateFolder.html"; string defaultTemplate = @"{{date}}"; string script = @" exports.transform = function (model){ return { date: new Date(new Date('2019-08-19T05:40:30.4629999Z')).toISOString() }; }"; var model = new object(); var item1 = new InternalManifestItem { FileWithoutExtension = "file", Key = "x.yml", DocumentType = "Conceptual", LocalPathFromRoot = "file.md", }; ProcessTemplate(templateName, null, new[] { item1 }, model, _outputFolder, Tuple.Create("default.html.tmpl", defaultTemplate), Tuple.Create("default.html.js", script) ); var outputFilePath1 = Path.Combine(_outputFolder, "file.html"); Assert.True(File.Exists(outputFilePath1)); Assert.Equal("2019-08-19T05:40:30.000Z", File.ReadAllText(outputFilePath1)); }
public void TestLiquidTemplateProcessSingleTemplateWithNoScriptShouldWork() { // 1. Prepare template var templateName = "NoScript.liquid"; string template = @" {% for item in model -%} {{ item.name }} {% endfor -%} "; var model = new { model = new[] { new { name = "test1" }, new { name = "test2" }, } }; var modelFileName = Path.Combine(_inputFolder, "TestLiquidTemplateProcessor_NoScript.yml"); var item = new InternalManifestItem { DocumentType = string.Empty, Key = modelFileName, FileWithoutExtension = Path.ChangeExtension(modelFileName, null), ResourceFile = modelFileName }; ProcessTemplate(templateName, null, new[] { item }, model, _outputFolder, Tuple.Create("default.liquid", template)); var outputFile = Path.Combine(_outputFolder, Path.ChangeExtension(modelFileName, string.Empty)); Assert.True(File.Exists(outputFile)); Assert.Equal(@" test1 test2 ", File.ReadAllText(outputFile)); }
public void TestMustacheTemplateProcessTemplateFolderWithDifferentTypeShouldWork() { var templateName = "TemplateFolder.html"; string defaultTemplate = @" default: {{#model}} {{name}} {{/model}} "; string conceptualTemplate = @" conceptual: {{#model}} {{name}} {{/model}} "; string script = @" exports.transform = function (model){ model.model.push({name:'test2'}); return model; }"; var model = new { model = new List <object> { new { name = "test1" }, } }; string inputFolder = null; var item1 = new InternalManifestItem { FileWithoutExtension = "TestTemplateProcessor_TemplateFolderWithDifferentType1", Key = "x.yml", DocumentType = "Conceptual" }; var item2 = new InternalManifestItem { DocumentType = string.Empty, FileWithoutExtension = "TestTemplateProcessor_TemplateFolderWithDifferentType2", Key = "y.yml" }; ProcessTemplate(templateName, inputFolder, new[] { item1, item2 }, model, _outputFolder, Tuple.Create("default.html.tmpl", defaultTemplate), Tuple.Create($"{templateName}/conceptual.md.tmpl", conceptualTemplate), Tuple.Create("default.html.js", script), Tuple.Create("conceptual.md.js", script) ); var outputFilePath1 = Path.Combine(_outputFolder, "TestTemplateProcessor_TemplateFolderWithDifferentType1.md"); Assert.True(File.Exists(outputFilePath1)); Assert.Equal(@" conceptual: test1 test2 ", File.ReadAllText(outputFilePath1)); var outputFilePath2 = Path.Combine(_outputFolder, "TestTemplateProcessor_TemplateFolderWithDifferentType2.html"); Assert.True(File.Exists(outputFilePath2)); Assert.Equal(@" default: test1 test2 ", File.ReadAllText(outputFilePath2)); }
public void TestMustacheTemplateProcessSingleTemplateWithRequireScriptShouldWork() { var templateName = "WithRequireScript.html"; string template = @" {{#model}} {{#result1}}result1 = true{{/result1}} {{#result2}}result2 = true{{/result2}} {{#result3}}result3 = true{{/result3}} {{/model}} "; string mainScript = @" var util = require('./util.js'); exports.transform = function (model){ var url = 'https://www.microsoft.com'; model.model.result1 = util.isAbsolutePath(url); model.model.result2 = util.isAbsolutePath(url); model.model.result3 = util.isAbsolutePath(url); return model; }"; string utilScript = @" exports.isAbsolutePath = isAbsolutePath; function isAbsolutePath(path) { return /^(\w+:)?\/\//g.test(path); } "; var model = new { model = new Dictionary <string, object>() }; var modelFileName = Path.Combine(_inputFolder, "TestTemplateProcessor_WithRequireScript.yml"); string inputFolder = null; var item = new InternalManifestItem { FileWithoutExtension = Path.ChangeExtension(modelFileName, null), DocumentType = string.Empty, Key = modelFileName, LocalPathFromRoot = modelFileName, }; ProcessTemplate(templateName, inputFolder, new[] { item }, model, _outputFolder, Tuple.Create("default.html.tmpl", template), Tuple.Create("default.html.js", mainScript), Tuple.Create("util.js", utilScript) ); var outputFilePath = Path.Combine(_outputFolder, Path.ChangeExtension(modelFileName, "html")); Assert.True(File.Exists(outputFilePath)); AssertEqualIgnoreCrlf(@" result1 = true result2 = true result3 = true ", File.ReadAllText(outputFilePath)); }
public void TestMustacheTemplateProcessSingleTemplateWithNoScriptWithPartialShouldWork() { // 1. Prepare template var templateName = "Subfolder/NoScriptWithPartial"; string template = @" {{#model}} {{name}} {{/model}} {{>partial1}} "; string partial1 = @"partial 1: {{>partial2}}"; string partial2 = @"partial 2: {{#model}} {{name}} {{/model}} "; var model = new { model = new[] { new { name = "test1" }, new { name = "test2" }, } }; var modelFileName = Path.Combine(_inputFolder, "TestTemplateProcessor_NoScriptWithPartial.yml"); var item = new InternalManifestItem { DocumentType = string.Empty, Key = modelFileName, FileWithoutExtension = Path.ChangeExtension(modelFileName, null), ResourceFile = modelFileName, LocalPathFromRoot = modelFileName, }; ProcessTemplate( templateName, null, new[] { item }, model, _outputFolder, Tuple.Create("default.tmpl", template), Tuple.Create("partial1.tmpl.partial", partial1), Tuple.Create("partial2.tmpl.partial", partial2)); var outputFile = Path.Combine(_outputFolder, Path.ChangeExtension(modelFileName, string.Empty)); Assert.True(File.Exists(outputFile)); AssertEqualIgnoreCrlf(@" test1 test2 partial 1: partial 2: test1 test2 ", File.ReadAllText(outputFile)); }
public void TestLiquidTemplateProcessSingleTemplateWithNoScriptWithIncludeShouldWork() { // 1. Prepare template var templateName = "NoScriptWithInclude.liquid"; string template = @" {% for item in model -%} {{ item.name }} {% endfor -%} {% include partial1 -%} "; string partial1 = @"partial 1: {% include partial2 -%}"; string partial2 = @"partial 2: {% for item in model -%} {{ item.name }} {% endfor -%} "; var model = new { model = new[] { new { name = "test1" }, new { name = "test2" }, } }; var modelFileName = Path.Combine(_inputFolder, "TestLiquidTemplateProcessor_NoScriptWithPartial.yml"); var item = new InternalManifestItem { DocumentType = string.Empty, Key = modelFileName, FileWithoutExtension = Path.ChangeExtension(modelFileName, null), ResourceFile = modelFileName, LocalPathFromRoot = modelFileName, }; ProcessTemplate( templateName, null, new[] { item }, model, _outputFolder, Tuple.Create("default.liquid", template), Tuple.Create("_partial1.liquid", partial1), Tuple.Create("_partial2.liquid", partial2)); var outputFile = Path.Combine(_outputFolder, Path.ChangeExtension(modelFileName, string.Empty)); Assert.True(File.Exists(outputFile)); AssertEqualIgnoreCrlf(@" test1 test2 partial 1: partial 2: test1 test2 ", File.ReadAllText(outputFile)); }
public SystemMetadata Generate(InternalManifestItem item) { var attrs = new SystemMetadata { Language = Constants.DefaultLanguage, }; string key = GetFileKey(item.Key); var file = (TypeForwardedToRelativePath)(item.FileWithoutExtension + item.Extension); attrs.RelativePathToRoot = (TypeForwardedToRelativePath.Empty).MakeRelativeTo(file); var fileWithoutWorkingFolder = file.RemoveWorkingFolder(); attrs.Path = fileWithoutWorkingFolder; // 1. Root Toc is always in the top directory of output folder var rootToc = _toc.FirstOrDefault(); if (rootToc != null) { var rootTocPath = rootToc.File.RemoveWorkingFolder(); if (rootTocPath.SubdirectoryCount == 0) { attrs.RootTocPath = rootTocPath; var rootTocRelativePath = rootTocPath.MakeRelativeTo(file); attrs.RelativePathToRootToc = rootTocRelativePath; attrs.RootTocKey = rootToc.Key; Logger.LogVerbose($"Root TOC file {rootTocPath} is found."); } else { Logger.LogVerbose($"Root TOC file from output folder is not found, the toppest TOC file is {rootTocPath}"); } } // 2. The algorithm of toc current article belongs to: // a. If toc can be found in TocMap, return that toc // b. Elsewise, get the nearest toc, **nearest** means nearest toc in **OUTPUT** folder var parentTocFiles = _context.GetTocFileKeySet(key)?.Select(s => new FileInfo(s, (TypeForwardedToRelativePath)_context.GetFilePath(s))); var parentToc = GetNearestToc(parentTocFiles, file) ?? GetDefaultToc(key); if (parentToc != null) { var parentTocPath = parentToc.File.RemoveWorkingFolder(); attrs.TocPath = parentTocPath; var tocRelativePath = parentTocPath.MakeRelativeTo(file); attrs.RelativePathToToc = tocRelativePath; attrs.TocKey = parentToc.Key; Logger.LogVerbose($"TOC file {parentTocPath} is found for {item.LocalPathFromRoot}."); } else { Logger.LogVerbose($"TOC file for {item.LocalPathFromRoot} is not found."); } return attrs; }
public void TestLiquidTemplateProcessSingleTemplateWithDependenciesShouldWork() { var templateName = "WithIncludes.liquid"; string template = @" {% ref reference1.html -%} {% ref reference2.html -%} {% for item in model -%} {{ item.name }} {% endfor -%} "; string script = @" exports.transform = function (model){ model.model.push({name:'test2'}); return model; }"; var model = new { model = new List <object> { new { name = "test1" }, } }; var modelFileName = Path.Combine(_inputFolder, "TestLiquidTemplateProcessor_WithIncludes.yml"); string inputFolder = null; var item = new InternalManifestItem { FileWithoutExtension = Path.ChangeExtension(modelFileName, null), DocumentType = string.Empty, Key = modelFileName, LocalPathFromRoot = modelFileName, }; ProcessTemplate(templateName, inputFolder, new[] { item }, model, _outputFolder, Tuple.Create("default.html.liquid", template), Tuple.Create("default.html.js", script), Tuple.Create("reference1.html", string.Empty), Tuple.Create("reference2.html", string.Empty) ); var outputFilePath = Path.Combine(_outputFolder, Path.ChangeExtension(modelFileName, "html")); Assert.True(File.Exists(outputFilePath)); Assert.True(File.Exists(Path.Combine(_outputFolder, "reference1.html"))); Assert.True(File.Exists(Path.Combine(_outputFolder, "reference2.html"))); AssertEqualIgnoreCrlf(@" test1 test2 ", File.ReadAllText(outputFilePath)); }
public void TestMustacheTemplateProcessInvalidTemplateShouldFail() { var templateName = "InvalidTemplate.html"; string inputFolder = null; var modelFileName = Path.Combine(_inputFolder, "TestTemplateProcessor_InvalidTemplate.yml"); var item = new InternalManifestItem { FileWithoutExtension = Path.ChangeExtension(modelFileName, null), DocumentType = string.Empty, Key = modelFileName }; ProcessTemplate(templateName, inputFolder, new[] { item }, new object(), _outputFolder, Tuple.Create("default.invalidtmpl", string.Empty), Tuple.Create("default.js", string.Empty), Tuple.Create("reference1.html", string.Empty), Tuple.Create("reference2.html", string.Empty) ); }
public void TestMustacheTemplateProcessSingleTemplateWithIncludesShouldWork() { var templateName = "WithIncludes.html"; string template = @" {{ !include('reference1.html') }} {{ !include('reference2.html') }} {{#model}} {{name}} {{/model}} "; string script = @" exports.transform = function (model){ model.model.push({name:'test2'}); return model; }"; var model = new { model = new List <object> { new { name = "test1" }, } }; var modelFileName = Path.Combine(_inputFolder, "TestTemplateProcessor_WithIncludes.yml"); string inputFolder = null; var item = new InternalManifestItem { FileWithoutExtension = Path.ChangeExtension(modelFileName, null), DocumentType = string.Empty, Key = modelFileName }; ProcessTemplate(templateName, inputFolder, new[] { item }, model, _outputFolder, Tuple.Create("default.html.tmpl", template), Tuple.Create("default.html.js", script), Tuple.Create("reference1.html", string.Empty), Tuple.Create("reference2.html", string.Empty) ); var outputFilePath = Path.Combine(_outputFolder, Path.ChangeExtension(modelFileName, "html")); Assert.True(File.Exists(outputFilePath)); Assert.True(File.Exists(Path.Combine(_outputFolder, "reference1.html"))); Assert.True(File.Exists(Path.Combine(_outputFolder, "reference2.html"))); Assert.Equal(@" test1 test2 ", File.ReadAllText(outputFilePath)); }
private IEnumerable<TransformModelOptions> GetOptionsForEachTemplate(InternalManifestItem item, IDocumentBuildContext context) { if (item == null) { yield break; } foreach (var template in Templates) { if (template.ContainsGetOptions) { var options = template.GetOptions(item.Model.Content); if (options != null) { yield return options; } } } }
private ManifestItem Process(string documentType, string fileName, object content, XRefSpec spec) { var reader = new LocalFileResourceReader(_templateFolder); var context = new DocumentBuildContext(_outputFolder); context.RegisterInternalXrefSpec(spec); var processor = new TemplateProcessor(reader, context, 64); var inputItem = new InternalManifestItem { DocumentType = documentType, Extension = "html", FileWithoutExtension = Path.GetFullPath(Path.Combine(_outputFolder, Path.GetFileNameWithoutExtension(fileName))), LocalPathFromRoot = fileName, Model = new ModelWithCache(content), }; return(processor.Process(new List <InternalManifestItem> { inputItem }, new ApplyTemplateSettings(_inputFolder, _outputFolder))[0]); }
public void TestMustacheTemplateWithScriptWithLongStringInModelShouldWork() { // https://github.com/sebastienros/jint/issues/357 var templateName = "TemplateFolder.html"; string defaultTemplate = @"{{name}}"; var name = "this is a looooooooooooooooooooooooooooooooooooog name"; var longName = string.Concat(Enumerable.Repeat(name, 20000)); string script = @" exports.transform = function (model){ return { name: JSON.stringify(model) }; }"; var model = new { model = new { name = longName, } }; string inputFolder = null; var item1 = new InternalManifestItem { FileWithoutExtension = "TestMustacheTemplateWithScriptWithLongStringInModelShouldWork", Key = "x.yml", DocumentType = "Conceptual", LocalPathFromRoot = "TestMustacheTemplateWithScriptWithLongStringInModelShouldWork.md", }; ProcessTemplate(templateName, inputFolder, new[] { item1 }, model, _outputFolder, Tuple.Create("default.html.tmpl", defaultTemplate), Tuple.Create("default.html.js", script) ); var outputFilePath1 = Path.Combine(_outputFolder, "TestMustacheTemplateWithScriptWithLongStringInModelShouldWork.html"); Assert.True(File.Exists(outputFilePath1)); Assert.Equal($"{{"model":{{"name":"{longName}"}},"__global":{{}}}}", File.ReadAllText(outputFilePath1)); }
public void JsRegexShouldNotShareStatusAmongFunctions() { // https://github.com/sebastienros/jint/issues/364 var templateName = "TemplateFolder.html"; string defaultTemplate = @"{{result1}},{{result2}}"; string script = @" exports.transform = function (model){ var url = 'https://www.example.com'; var result1 = isAbsolutePath(url); var result2 = isAbsolutePath(url); function isAbsolutePath(path) { return /^(\w+:)?\/\//g.test(path); } return { result1: result1, result2: result2 }; }"; var model = new object(); var item1 = new InternalManifestItem { FileWithoutExtension = "file", Key = "x.yml", DocumentType = "Conceptual", LocalPathFromRoot = "file.md", }; ProcessTemplate(templateName, null, new[] { item1 }, model, _outputFolder, Tuple.Create("default.html.tmpl", defaultTemplate), Tuple.Create("default.html.js", script) ); var outputFilePath1 = Path.Combine(_outputFolder, "file.html"); Assert.True(File.Exists(outputFilePath1)); Assert.Equal("True,True", File.ReadAllText(outputFilePath1)); }
public void TestLiquidTemplateProcessSingleTemplateWithDependenciesShouldWork() { var templateName = "WithIncludes.liquid"; string template = @" {% ref reference1.html -%} {% ref reference2.html -%} {% for item in model -%} {{ item.name }} {% endfor -%} "; string script = @" exports.transform = function (model){ model.model.push({name:'test2'}); return model; }"; var model = new { model = new List<object> { new {name = "test1"}, } }; var modelFileName = Path.Combine(_inputFolder, "TestLiquidTemplateProcessor_WithIncludes.yml"); string inputFolder = null; var item = new InternalManifestItem { FileWithoutExtension = Path.ChangeExtension(modelFileName, null), DocumentType = string.Empty, Key = modelFileName, LocalPathFromRoot = modelFileName, }; ProcessTemplate(templateName, inputFolder, new[] { item }, model, _outputFolder, Tuple.Create("default.html.liquid", template), Tuple.Create("default.html.js", script), Tuple.Create("reference1.html", string.Empty), Tuple.Create("reference2.html", string.Empty) ); var outputFilePath = Path.Combine(_outputFolder, Path.ChangeExtension(modelFileName, "html")); Assert.True(File.Exists(outputFilePath)); Assert.True(File.Exists(Path.Combine(_outputFolder, "reference1.html"))); Assert.True(File.Exists(Path.Combine(_outputFolder, "reference2.html"))); Assert.Equal(@" test1 test2 ", File.ReadAllText(outputFilePath)); }
public void TestLiquidTemplateProcessTemplateFolderWithDifferentTypeShouldWork() { var templateName = "TemplateFolder.liquid"; string defaultTemplate = @" default: {% for item in model -%} {{ item.name }} {% endfor -%} "; string conceptualTemplate = @" conceptual: {% for item in model -%} {{ item.name }} {% endfor -%} "; string script = @" exports.transform = function (model){ model.model.push({name:'test2'}); return model; }"; var model = new { model = new List<object> { new {name = "test1"}, }, another = new Dictionary<string, object> { ["key1"] = new { name = "test3" }, ["key2"] = new { name = "test4" } } }; string inputFolder = null; var item1 = new InternalManifestItem { FileWithoutExtension = "TestLiquidTemplateProcessor_TemplateFolderWithDifferentType1", Key = "x.yml", DocumentType = "Conceptual", LocalPathFromRoot = "TestLiquidTemplateProcessor_TemplateFolderWithDifferentType1.md", }; var item2 = new InternalManifestItem { DocumentType = string.Empty, FileWithoutExtension = "TestLiquidTemplateProcessor_TemplateFolderWithDifferentType2", Key = "y.yml", LocalPathFromRoot = "TestLiquidTemplateProcessor_TemplateFolderWithDifferentType2.md", }; ProcessTemplate(templateName, inputFolder, new[] { item1, item2 }, model, _outputFolder, Tuple.Create("default.html.liquid", defaultTemplate), Tuple.Create($"{templateName}/conceptual.md.liquid", conceptualTemplate), Tuple.Create("default.html.js", script), Tuple.Create("conceptual.md.js", script) ); var outputFilePath1 = Path.Combine(_outputFolder, "TestLiquidTemplateProcessor_TemplateFolderWithDifferentType1.md"); Assert.True(File.Exists(outputFilePath1)); Assert.Equal(@" conceptual: test1 test2 ", File.ReadAllText(outputFilePath1)); var outputFilePath2 = Path.Combine(_outputFolder, "TestLiquidTemplateProcessor_TemplateFolderWithDifferentType2.html"); Assert.True(File.Exists(outputFilePath2)); Assert.Equal(@" default: test1 test2 ", File.ReadAllText(outputFilePath2)); }
public void TestMustacheTemplateProcessSingleTemplateWithNoScriptShouldWork() { // 1. Prepare template var templateName = "NoScript"; string template = @" {{#model}} name1={{name1}}, name2={{name2}}; {{/model}} "; var model = new { model = new object[] { new {name1 = "test1"}, new {name2 = "test2"}, } }; var modelFileName = Path.Combine(_inputFolder, "TestTemplateProcessor_NoScript.yml"); var item = new InternalManifestItem { DocumentType = string.Empty, Key = modelFileName, FileWithoutExtension = Path.ChangeExtension(modelFileName, null), ResourceFile = modelFileName, LocalPathFromRoot = modelFileName, }; ProcessTemplate(templateName, null, new[] { item }, model, _outputFolder, Tuple.Create("default.tmpl", template)); var outputFile = Path.Combine(_outputFolder, Path.ChangeExtension(modelFileName, string.Empty)); Assert.True(File.Exists(outputFile)); Assert.Equal(@" name1=test1, name2=; name1=, name2=test2; ", File.ReadAllText(outputFile)); }
public void TestMustacheTemplateWithMasterPageShouldWork() { // 1. Prepare template var templateName = "Subfolder/WithMasterPage"; string template = @" {{!master('_layout/master.html')}} {{!master(' _layout/invalid1.html ')}} {{#model}} {{name}} {{/model}} {{>partial1}} {{!master( _layout/invalid2.html )}} "; string partial1 = @"partial 1: {{>partial2}}"; string partial2 = @"partial 2: {{#model}} {{name}} {{/model}} "; string master = @" {{ !include('reference1.html') }} Hello Master {{!body}} Hello Body {{!body}} "; var model = new { model = new[] { new { name = "test1" }, new { name = "test2" }, } }; var modelFileName = Path.Combine(_inputFolder, "TestTemplateProcessor_WithMasterPage.yml"); var item = new InternalManifestItem { DocumentType = string.Empty, Key = modelFileName, FileWithoutExtension = Path.ChangeExtension(modelFileName, null), ResourceFile = modelFileName, LocalPathFromRoot = modelFileName, }; ProcessTemplate( templateName, null, new[] { item }, model, _outputFolder, Tuple.Create("default.tmpl", template), Tuple.Create("_layout/master.html", master), Tuple.Create("reference1.html", string.Empty), Tuple.Create("partial1.tmpl.partial", partial1), Tuple.Create("partial2.tmpl.partial", partial2)); var outputFile = Path.Combine(_outputFolder, Path.ChangeExtension(modelFileName, string.Empty)); Assert.True(File.Exists(Path.Combine(_outputFolder, "reference1.html"))); Assert.True(File.Exists(outputFile)); AssertEqualIgnoreCrlf(@" Hello Master test1 test2 partial 1: partial 2: test1 test2 Hello Body test1 test2 partial 1: partial 2: test1 test2 ", File.ReadAllText(outputFile)); }
/// <summary> /// Must guarantee thread safety /// </summary> /// <param name="item"></param> /// <returns></returns> internal ManifestItem Transform(InternalManifestItem item) { if (item.Model == null || item.Model.Content == null) throw new ArgumentNullException("Content for item.Model should not be null!"); var model = ConvertObjectToDictionary(item.Model.Content); model = AppendGlobalMetadata(model); if (_settings.Options.HasFlag(ApplyTemplateOptions.ExportRawModel)) { ExportModel(model, item.FileWithoutExtension, _settings.RawModelExportSettings); } var manifestItem = new ManifestItem { DocumentType = item.DocumentType, SourceRelativePath = item.LocalPathFromRoot, OutputFiles = new Dictionary<string, OutputFileInfo>(), Metadata = item.Metadata, }; var outputDirectory = _settings.OutputFolder ?? Directory.GetCurrentDirectory(); // 1. process resource if (item.ResourceFile != null) { // Resource file has already been processed in its plugin manifestItem.OutputFiles.Add("resource", new OutputFileInfo { RelativePath = item.ResourceFile, LinkToPath = null, Hash = null }); } // 2. process model var templateBundle = _templateCollection[item.DocumentType]; if (templateBundle == null) { return manifestItem; } HashSet<string> missingUids = new HashSet<string>(); // Must convert to JObject first as we leverage JsonProperty as the property name for the model foreach (var template in templateBundle.Templates) { if (!template.ContainsTemplateRenderer) { continue; } try { var extension = template.Extension; string outputFile = item.FileWithoutExtension + extension; string outputPath = Path.Combine(outputDirectory, outputFile); var dir = Path.GetDirectoryName(outputPath); if (!string.IsNullOrEmpty(dir)) Directory.CreateDirectory(dir); object viewModel = null; try { viewModel = template.TransformModel(model); } catch (Exception e) { // save raw model for further investigation: var exportSettings = ApplyTemplateSettings.RawModelExportSettingsForDebug; var rawModelPath = ExportModel(model, item.FileWithoutExtension, exportSettings); var message = $"Error transforming model \"{rawModelPath}\" generated from \"{item.LocalPathFromRoot}\" using \"{template.ScriptName}\": {e.Message}"; Logger.LogError(message); throw new DocumentException(message, e); } string result; try { result = template.Transform(viewModel); } catch (Exception e) { // save view model for further investigation: var exportSettings = ApplyTemplateSettings.ViewModelExportSettingsForDebug; var viewModelPath = ExportModel(viewModel, outputFile, exportSettings); var message = $"Error applying template \"{template.Name}\" to view model \"{viewModelPath}\" generated from \"{item.LocalPathFromRoot}\": {e.Message}"; Logger.LogError(message); throw new DocumentException(message, e); } if (_settings.Options.HasFlag(ApplyTemplateOptions.ExportViewModel)) { ExportModel(viewModel, outputFile, _settings.ViewModelExportSettings); } if (_settings.Options.HasFlag(ApplyTemplateOptions.TransformDocument)) { if (string.IsNullOrWhiteSpace(result)) { // TODO: WHAT to do if is transformed to empty string? STILL creat empty file? var exportSettings = ApplyTemplateSettings.ViewModelExportSettingsForDebug; var viewModelPath = ExportModel(viewModel, outputFile, exportSettings); Logger.LogWarning($"Model \"{viewModelPath}\" is transformed to empty string with template \"{template.Name}\""); } TransformDocument(result ?? string.Empty, extension, _context, outputPath, outputFile, missingUids, manifestItem); Logger.LogDiagnostic($"Transformed model \"{item.LocalPathFromRoot}\" to \"{outputPath}\"."); } } catch (PathTooLongException e) { var message = $"Error processing {item.LocalPathFromRoot}: {e.Message}"; throw new PathTooLongException(message, e); } } if (missingUids.Count > 0) { var uids = string.Join(", ", missingUids.Select(s => $"\"{s}\"")); Logger.LogWarning($"Invalid cross reference {uids}.", null, item.LocalPathFromRoot); } return manifestItem; }
internal TransformModelOptions GetOptions(InternalManifestItem item, IDocumentBuildContext context) { return MergeOptions(GetOptionsForEachTemplate(item, context)); }
public void TestLiquidTemplateProcessSingleTemplateWithNoScriptWithIncludeShouldWork() { // 1. Prepare template var templateName = "NoScriptWithInclude.liquid"; string template = @" {% for item in model -%} {{ item.name }} {% endfor -%} {% include partial1 -%} "; string partial1 = @"partial 1: {% include partial2 -%}"; string partial2 = @"partial 2: {% for item in model -%} {{ item.name }} {% endfor -%} "; var model = new { model = new[] { new {name = "test1"}, new {name = "test2"}, } }; var modelFileName = Path.Combine(_inputFolder, "TestLiquidTemplateProcessor_NoScriptWithPartial.yml"); var item = new InternalManifestItem { DocumentType = string.Empty, Key = modelFileName, FileWithoutExtension = Path.ChangeExtension(modelFileName, null), ResourceFile = modelFileName, LocalPathFromRoot = modelFileName, }; ProcessTemplate( templateName, null, new[] { item }, model, _outputFolder, Tuple.Create("default.liquid", template), Tuple.Create("_partial1.liquid", partial1), Tuple.Create("_partial2.liquid", partial2)); var outputFile = Path.Combine(_outputFolder, Path.ChangeExtension(modelFileName, string.Empty)); Assert.True(File.Exists(outputFile)); Assert.Equal(@" test1 test2 partial 1: partial 2: test1 test2 ", File.ReadAllText(outputFile)); }
public void TestLiquidTemplateWithMasterPageShouldWork() { // 1. Prepare template var templateName = "Subfolder/LiquidWithMasterPage"; string template = @" {% master _layout/master.html -%} {% master _layout/master.html -%} {% for item in model -%} {{ item.name }} {% endfor -%} {% include partial1 -%} "; string partial1 = @"partial 1: {% include partial2 -%}"; string partial2 = @"partial 2: {% for item in model -%} {{ item.name }} {% endfor -%} "; string master = @" {% ref reference1.html -%} Hello Master {% include partial1 -%} {%- body %} "; var model = new { model = new[] { new { name = "test1" }, new { name = "test2" }, } }; var modelFileName = Path.Combine(_inputFolder, "TestTemplateProcessor_LiquidWithMasterPage.yml"); var item = new InternalManifestItem { DocumentType = string.Empty, Key = modelFileName, FileWithoutExtension = Path.ChangeExtension(modelFileName, null), ResourceFile = modelFileName, LocalPathFromRoot = modelFileName, }; ProcessTemplate( templateName, null, new[] { item }, model, _outputFolder, Tuple.Create("default.liquid", template), Tuple.Create("_layout/master.html", master), Tuple.Create("reference1.html", string.Empty), Tuple.Create("_partial1.liquid", partial1), Tuple.Create("_partial2.liquid", partial2)); var outputFile = Path.Combine(_outputFolder, Path.ChangeExtension(modelFileName, string.Empty)); Assert.True(File.Exists(Path.Combine(_outputFolder, "reference1.html"))); Assert.True(File.Exists(outputFile)); AssertEqualIgnoreCrlf(@" Hello Master partial 1: partial 2: test1 test2 test1 test2 partial 1: partial 2: test1 test2 ", File.ReadAllText(outputFile)); }
public ManifestItemWithContext(InternalManifestItem item, FileModel model, IDocumentProcessor processor, TemplateBundle bundle) { Item = item; FileModel = model; Processor = processor; TemplateBundle = bundle; }
public void TestLiquidTemplateProcessTemplateFolderWithDifferentTypeShouldWork() { var templateName = "TemplateFolder.liquid"; string defaultTemplate = @" default: {% for item in model -%} {{ item.name }} {% endfor -%} "; string conceptualTemplate = @" conceptual: {% for item in model -%} {{ item.name }} {% endfor -%} "; string script = @" exports.transform = function (model){ model.model.push({name:'test2'}); return model; }"; var model = new { model = new List <object> { new { name = "test1" }, }, another = new Dictionary <string, object> { ["key1"] = new { name = "test3" }, ["key2"] = new { name = "test4" } } }; string inputFolder = null; var item1 = new InternalManifestItem { FileWithoutExtension = "TestLiquidTemplateProcessor_TemplateFolderWithDifferentType1", Key = "x.yml", DocumentType = "Conceptual", LocalPathFromRoot = "TestLiquidTemplateProcessor_TemplateFolderWithDifferentType1.md", }; var item2 = new InternalManifestItem { DocumentType = string.Empty, FileWithoutExtension = "TestLiquidTemplateProcessor_TemplateFolderWithDifferentType2", Key = "y.yml", LocalPathFromRoot = "TestLiquidTemplateProcessor_TemplateFolderWithDifferentType2.md", }; ProcessTemplate(templateName, inputFolder, new[] { item1, item2 }, model, _outputFolder, Tuple.Create("default.html.liquid", defaultTemplate), Tuple.Create("conceptual.md.liquid", conceptualTemplate), Tuple.Create("default.html.js", script), Tuple.Create("conceptual.md.js", script) ); var outputFilePath1 = Path.Combine(_outputFolder, "TestLiquidTemplateProcessor_TemplateFolderWithDifferentType1.md"); Assert.True(File.Exists(outputFilePath1)); AssertEqualIgnoreCrlf(@" conceptual: test1 test2 ", File.ReadAllText(outputFilePath1)); var outputFilePath2 = Path.Combine(_outputFolder, "TestLiquidTemplateProcessor_TemplateFolderWithDifferentType2.html"); Assert.True(File.Exists(outputFilePath2)); AssertEqualIgnoreCrlf(@" default: test1 test2 ", File.ReadAllText(outputFilePath2)); }
public void TestMustacheTemplateProcessInvalidTemplateShouldFail() { var templateName = "InvalidTemplate.html"; string inputFolder = null; var modelFileName = Path.Combine(_inputFolder, "TestTemplateProcessor_InvalidTemplate.yml"); var item = new InternalManifestItem { FileWithoutExtension = Path.ChangeExtension(modelFileName, null), DocumentType = string.Empty, Key = modelFileName, LocalPathFromRoot = modelFileName, }; ProcessTemplate(templateName, inputFolder, new[] { item }, new object(), _outputFolder, Tuple.Create("default.invalidtmpl", string.Empty), Tuple.Create("default.js", string.Empty), Tuple.Create("reference1.html", string.Empty), Tuple.Create("reference2.html", string.Empty) ); }