Esempio n. 1
0
        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;
        }
Esempio n. 2
0
        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;
                    }
                }
            }
        }
Esempio n. 3
0
 public ManifestItemWithContext(InternalManifestItem item, FileModel model, IDocumentProcessor processor, TemplateBundle bundle)
 {
     Item = item;
     FileModel = model;
     Processor = processor;
     TemplateBundle = bundle;
 }
Esempio n. 4
0
 internal TransformModelOptions GetOptions(InternalManifestItem item, IDocumentBuildContext context)
 {
     return MergeOptions(GetOptionsForEachTemplate(item, context));
 }
Esempio n. 5
0
        /// <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;
        }
Esempio n. 6
0
        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));
        }
Esempio n. 7
0
        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));
        }
Esempio n. 8
0
        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));
        }
Esempio n. 9
0
        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));
        }
Esempio n. 10
0
 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)
         );
 }