private static void ProcessTemplate(string templateName, string inputFolder, IEnumerable <InternalManifestItem> items, object model, string outputFolder, params Tuple <string, string>[] templateFiles) { var rootTemplateFolder = "tmpl"; var templateFolder = Path.Combine(rootTemplateFolder, templateName); if (Directory.Exists(templateFolder)) { Directory.Delete(templateFolder, true); } WriteTemplate(templateFolder, templateFiles); using (var resource = new ResourceFinder(null, null).Find(templateFolder)) { var processor = new TemplateProcessor(resource, 4); var context = new DocumentBuildContext(inputFolder); foreach (var item in items) { if (item.ResourceFile != null) { var dir = Path.GetDirectoryName(item.ResourceFile); if (!string.IsNullOrEmpty(dir)) { Directory.CreateDirectory(dir); } File.Create(item.ResourceFile).Dispose(); } if (string.IsNullOrEmpty(item.InputFolder)) { item.InputFolder = Environment.CurrentDirectory; } item.Model = new DocAsCode.Plugins.ModelWithCache(model); } var settings = new ApplyTemplateSettings(inputFolder, outputFolder); processor.Process(items.ToList(), context, settings); } }
public SystemAttributes(DocumentBuildContext context, ManifestItem item, string lang) { Language = lang; GetTocInfo(context, item); TocRelativePath = TocPath == null ? null : ((RelativePath)TocPath).MakeRelativeTo((RelativePath)item.ModelFile); RootTocRelativePath = RootTocPath == null ? null : ((RelativePath)RootTocPath).MakeRelativeTo((RelativePath)item.ModelFile); RelativePathToRoot = (RelativePath.Empty).MakeRelativeTo((RelativePath)item.ModelFile); }
private ParseResult InternalExec(BuildJsonConfig config, RunningContext context) { var parameters = ConfigToParameter(config); if (parameters.Files.Count == 0) { return(new ParseResult(ResultLevel.Warning, "No files found, nothing is to be generated")); } try { _builder.Build(parameters); } catch (AggregateDocumentException aggEx) { return(new ParseResult(ResultLevel.Warning, "following document error:" + Environment.NewLine + string.Join(Environment.NewLine, from ex in aggEx.InnerExceptions select ex.Message))); } catch (DocumentException ex) { return(new ParseResult(ResultLevel.Warning, "document error:" + ex.Message)); } var documentContext = DocumentBuildContext.DeserializeFrom(parameters.OutputBaseDir); var assembly = typeof(Program).Assembly; if (config.Templates == null || config.Templates.Count == 0) { config.Templates = new ListWithStringFallback { Constants.DefaultTemplateName }; } // If RootOutput folder is specified from command line, use it instead of the base directory var outputFolder = Path.Combine(config.OutputFolder ?? config.BaseDirectory ?? string.Empty, config.Destination ?? string.Empty); using (var manager = new TemplateManager(assembly, "Template", config.Templates, config.Themes, config.BaseDirectory)) { manager.ProcessTemplateAndTheme(documentContext, outputFolder, true); } // TODO: SEARCH DATA if (config.Serve) { ServeCommand.Serve(outputFolder, config.Port); } return(ParseResult.SuccessResult); }
private static void TranformHtml(DocumentBuildContext context, string transformed, string relativeModelPath, string outputPath) { // Update HREF and XREF var internalXref = context.XRefSpecMap; var externalXref = context.ExternalXRefSpec; HtmlAgilityPack.HtmlDocument html = new HtmlAgilityPack.HtmlDocument(); html.LoadHtml(transformed); var srcNodes = html.DocumentNode.SelectNodes("//*/@src"); if (srcNodes != null) { foreach (var link in srcNodes) { UpdateSrc(link, context.FileMap, s => UpdateFilePath(s, relativeModelPath)); } } var hrefNodes = html.DocumentNode.SelectNodes("//*/@href"); if (hrefNodes != null) { foreach (var link in hrefNodes) { // xref is generated by docfx, and is lower-cased if (link.Name == "xref") { UpdateXref(link, internalXref, externalXref, s => UpdateFilePath(s, relativeModelPath), Language); } else { UpdateHref(link, context.FileMap, s => UpdateFilePath(s, relativeModelPath)); } } } // Save with extension changed var subDirectory = Path.GetDirectoryName(outputPath); if (!string.IsNullOrEmpty(subDirectory) && !Directory.Exists(subDirectory)) { Directory.CreateDirectory(subDirectory); } html.Save(outputPath, Encoding.UTF8); }
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 static void UpdateFileMap(DocumentBuildContext context, string outputDirectory, TemplateCollection templateCollection) { //update internal XrefMap if (context.XRefSpecMap != null) { foreach (var pair in context.XRefSpecMap) { string targetFilePath; if (context.FileMap.TryGetValue(pair.Value.Href, out targetFilePath)) { pair.Value.Href = targetFilePath; } else { Logger.LogWarning($"{pair.Value.Href} is not found in .filemap"); } } } context.SetExternalXRefSpec(); }
public List <TemplateManifestItem> Transform(List <ManifestItem> items, DocumentBuildContext context, ApplyTemplateSettings settings) { var documentTypes = items.Select(s => s.DocumentType).Distinct().Where(s => s != "Resource" && Templates[s] == null); if (documentTypes.Any()) { Logger.LogWarning($"There is no template processing document type(s): {documentTypes.ToDelimitedString()}"); } var manifest = new ConcurrentBag <TemplateManifestItem>(); items.RunAll(item => { var manifestItem = TransformItem(item, context, settings); if (manifestItem != null) { manifest.Add(manifestItem); } }, Constants.DefaultParallelism); return(manifest.ToList()); }
private void GetTocInfo(DocumentBuildContext context, ManifestItem item) { string relativePath = item.OriginalFile; var tocMap = context.TocMap; var fileMap = context.FileMap; HashSet <string> parentTocs; string parentToc = null; string rootToc = null; string currentPath = ((RelativePath)relativePath).GetPathFromWorkingFolder(); while (tocMap.TryGetValue(currentPath, out parentTocs) && parentTocs.Count > 0) { // Get the first toc only currentPath = parentTocs.First(); rootToc = currentPath; if (parentToc == null) { parentToc = currentPath; } currentPath = ((RelativePath)currentPath).GetPathFromWorkingFolder(); } if (rootToc != null) { rootToc = fileMap[((RelativePath)rootToc).GetPathFromWorkingFolder()]; PathUtility.TryGetPathFromWorkingFolder(rootToc, out rootToc); RootTocPath = rootToc; } if (parentToc == null) { TocPath = RootTocPath; } else { parentToc = fileMap[((RelativePath)parentToc).GetPathFromWorkingFolder()]; PathUtility.TryGetPathFromWorkingFolder(parentToc, out parentToc); TocPath = parentToc; } }
public void ProcessTemplateAndTheme(DocumentBuildContext context, string outputDirectory, bool overwrite) { if (_templateProcessor != null) { Logger.Log(LogLevel.Verbose, "Template resource found, starting applying template."); _templateProcessor.Process(context, outputDirectory); } if (_themeResource != null) { Logger.Log(LogLevel.Verbose, "Theme resource found, starting copying theme."); foreach (var resourceName in _themeResource.Names) { using (var stream = _themeResource.GetResourceStream(resourceName)) { var outputPath = Path.Combine(outputDirectory, resourceName); CopyResource(stream, outputPath, overwrite); Logger.Log(LogLevel.Info, $"Theme resource {resourceName} copied to {outputPath}."); } } } }
private void ProcessTemplate(DocumentBuildContext context, string outputDirectory) { if (_templates == null || _templates.Count == 0) { Logger.Log(LogLevel.Info, "Template is not specified, files will not be transformed."); return; } using (var templateResource = new CompositeResourceCollectionWithOverridden(_templates.Select(s => _finder.Find(s)).Where(s => s != null))) { if (templateResource.IsEmpty) { Logger.Log(LogLevel.Warning, $"No template resource found for [{_templates.ToDelimitedString()}]."); } else { Logger.Log(LogLevel.Verbose, "Template resource found, starting applying template."); using (var processor = new TemplateProcessor(templateResource)) { processor.Process(context, outputDirectory); } } } }
// TODO: remove public void Process(DocumentBuildContext context, string outputDirectory) { var baseDirectory = context.BuildOutputFolder; if (string.IsNullOrEmpty(outputDirectory)) { outputDirectory = Environment.CurrentDirectory; } if (string.IsNullOrEmpty(baseDirectory)) { baseDirectory = Environment.CurrentDirectory; } if (!Directory.Exists(outputDirectory)) { Directory.CreateDirectory(outputDirectory); } // 1. Copy dependent files with path relative to the base output directory ProcessDependencies(outputDirectory); UpdateFileMap(context, outputDirectory, Templates); List <TemplateManifestItem> manifest = new List <TemplateManifestItem>(); // 3. Process every model and save to output directory foreach (var item in context.Manifest) { var manifestItem = Transform(context, item, Templates, outputDirectory, true, s => s + ".json"); manifest.Add(manifestItem); } // Save manifest var manifestPath = Path.Combine(outputDirectory, ManifestFileName); JsonUtility.Serialize(manifestPath, manifest); Logger.Log(LogLevel.Verbose, $"Manifest file saved to {manifestPath}."); }
private static void ProcessTemplate(string templateName, string inputFolder, IEnumerable <ManifestItem> items, object model, string outputFolder, params Tuple <string, string>[] templateFiles) { var rootTemplateFolder = "tmpl"; var templateFolder = Path.Combine(rootTemplateFolder, templateName); if (Directory.Exists(templateFolder)) { Directory.Delete(templateFolder, true); } WriteTemplate(templateFolder, templateFiles); foreach (var item in items) { var modelPath = Path.Combine(inputFolder ?? string.Empty, item.ModelFile); WriteModel(modelPath, model); } using (var resource = new ResourceFinder(null, null).Find(templateFolder)) { var processor = new TemplateProcessor(resource); var context = new DocumentBuildContext(inputFolder); context.Manifest.AddRange(items); processor.Process(context, outputFolder); } }
public void TestBuildWithXrefService() { var fakeResponseHandler = new FakeResponseHandler(); fakeResponseHandler.AddFakeResponse(new Uri("http://example.org/test1"), new HttpResponseMessage { StatusCode = HttpStatusCode.OK, Content = new StringContent("[]") }); fakeResponseHandler.AddFakeResponse(new Uri("http://example.org/test2"), new HttpResponseMessage { StatusCode = HttpStatusCode.OK, Content = new StringContent("[{'uid':'csharp_coding_standards', 'name':'C# Coding Standards', 'href':'http://dotnet.github.io/docfx/guideline/csharp_coding_standards.html'}]") }); var httpClient = new HttpClient(fakeResponseHandler); var dbc = new DocumentBuildContext(""); var result = dbc.QueryByHttpRequestAsync(httpClient, "http://example.org/test1", "xx").Result; Assert.Equal(0, result.Count); result = dbc.QueryByHttpRequestAsync(httpClient, "http://example.org/test2", "xx").Result; Assert.Equal("csharp_coding_standards", result[0].Uid); }
public void ProcessTemplateAndTheme(DocumentBuildContext context, string outputDirectory, bool overwrite) { ProcessTemplate(context, outputDirectory); ProcessTheme(outputDirectory, overwrite); }
public void Process(DocumentBuildContext context, string outputDirectory) { var baseDirectory = context.BuildOutputFolder; if (string.IsNullOrEmpty(outputDirectory)) { outputDirectory = Environment.CurrentDirectory; } if (string.IsNullOrEmpty(baseDirectory)) { baseDirectory = Environment.CurrentDirectory; } if (!Directory.Exists(outputDirectory)) { Directory.CreateDirectory(outputDirectory); } // 1. Copy dependent files with path relative to the base output directory ProcessDependencies(outputDirectory); Dictionary <string, HashSet <string> > unProcessedType = new Dictionary <string, HashSet <string> >(StringComparer.OrdinalIgnoreCase); Dictionary <string, string> extMapping = new Dictionary <string, string>(); // 2. Get extension for each item foreach (var item in context.Manifest) { if (item.ModelFile == null) { throw new ArgumentNullException("Model file path must be specified!"); } if (item.DocumentType == null) { throw new ArgumentNullException($"Document type is not allowed to be NULL for ${item.ModelFile}!"); } // NOTE: Resource is not supported for applying templates if (item.DocumentType.Equals("Resource", StringComparison.OrdinalIgnoreCase)) { continue; } var templates = _templates[item.DocumentType]; // Get default template extension if (templates == null || templates.Count == 0) { HashSet <string> unProcessedFiles; if (unProcessedType.TryGetValue(item.DocumentType, out unProcessedFiles)) { unProcessedFiles.Add(item.ModelFile); } else { unProcessedType[item.DocumentType] = new HashSet <string>(FilePathComparer.OSPlatformSensitiveComparer) { item.ModelFile }; } } else { var defaultTemplate = templates.FirstOrDefault(s => s.IsPrimary) ?? templates[0]; string key = ((RelativePath)item.OriginalFile).GetPathFromWorkingFolder(); string value; if (context.FileMap.TryGetValue(key, out value)) { context.FileMap[key] = Path.ChangeExtension(value, defaultTemplate.Extension); extMapping[key] = defaultTemplate.Extension; } else { Logger.Log(LogLevel.Warning, $"{key} is not found in .filemap"); } } } //update internal XrefMap if (context.XRefSpecMap != null) { foreach (var pair in context.XRefSpecMap) { string ext; if (extMapping.TryGetValue(pair.Value.Href, out ext)) { pair.Value.Href = Path.ChangeExtension(pair.Value.Href, ext); } } } if (unProcessedType.Count > 0) { StringBuilder sb = new StringBuilder("There is no template processing:"); foreach (var type in unProcessedType) { sb.AppendLine($"- Document type: \"{type.Key}\""); sb.AppendLine($"- Files:"); foreach (var file in type.Value) { sb.AppendLine($" -\"{file}\""); } } Logger.Log(LogLevel.Warning, sb.ToString());// not processed but copied to '{modelOutputPath}'"); } List <TemplateManifestItem> manifest = new List <TemplateManifestItem>(); // 3. Process every model and save to output directory foreach (var item in context.Manifest) { var manifestItem = new TemplateManifestItem { DocumentType = item.DocumentType, OriginalFile = item.LocalPathFromRepoRoot, OutputFiles = new Dictionary <string, string>() }; try { var templates = _templates[item.DocumentType]; // 1. process model if (templates == null) { // TODO: what if template to transform the type is not found? DO NOTHING? // CopyFile(modelFile, modelOutputPath); } else { var modelFile = Path.Combine(baseDirectory, item.ModelFile); var systemAttrs = new SystemAttributes(context, item, TemplateProcessor.Language); foreach (var template in templates) { var extension = template.Extension; string outputFile = Path.ChangeExtension(item.ModelFile, extension); string outputPath = Path.Combine(outputDirectory ?? string.Empty, outputFile); var dir = Path.GetDirectoryName(outputPath); if (!string.IsNullOrEmpty(dir)) { Directory.CreateDirectory(dir); } var transformed = template.Transform(modelFile, systemAttrs); if (!string.IsNullOrWhiteSpace(transformed)) { if (extension.Equals(".html", StringComparison.OrdinalIgnoreCase)) { TranformHtml(context, transformed, item.ModelFile, outputPath); } else { File.WriteAllText(outputPath, transformed, Encoding.UTF8); } Logger.Log(LogLevel.Verbose, $"Transformed model \"{item.ModelFile}\" to \"{outputPath}\"."); } else { // TODO: WHAT to do if is transformed to empty string? STILL creat empty file? Logger.Log(LogLevel.Warning, $"Model \"{item.ModelFile}\" is transformed to empty string with template \"{template.Name}\""); File.WriteAllText(outputPath, string.Empty); } manifestItem.OutputFiles.Add(extension, outputFile); } } // 2. process resource if (item.ResourceFile != null) { manifestItem.OutputFiles.Add("resource", item.ResourceFile); PathUtility.CopyFile(Path.Combine(baseDirectory, item.ResourceFile), Path.Combine(outputDirectory, item.ResourceFile), true); } } catch (Exception e) { Logger.Log(LogLevel.Warning, $"Unable to transform {item.ModelFile}: {e.Message}. Ignored."); } manifest.Add(manifestItem); } // Save manifest var manifestPath = Path.Combine(outputDirectory, ManifestFileName); JsonUtility.Serialize(manifestPath, manifest); Logger.Log(LogLevel.Verbose, $"Manifest file saved to {manifestPath}."); }
public static TemplateManifestItem Transform(DocumentBuildContext context, ManifestItem item, TemplateCollection templateCollection, string outputDirectory, bool exportMetadata, Func <string, string> metadataFilePathProvider) { var baseDirectory = context.BuildOutputFolder ?? string.Empty; var manifestItem = new TemplateManifestItem { DocumentType = item.DocumentType, OriginalFile = item.LocalPathFromRepoRoot, OutputFiles = new Dictionary <string, string>() }; if (templateCollection == null || templateCollection.Count == 0) { return(manifestItem); } try { var model = item.Model?.Content; var templates = templateCollection[item.DocumentType]; // 1. process model if (templates == null) { // Logger.LogWarning($"There is no template processing {item.DocumentType} document \"{item.LocalPathFromRepoRoot}\""); } else { var modelFile = Path.Combine(baseDirectory, item.ModelFile); var systemAttrs = new SystemAttributes(context, item, TemplateProcessor.Language); foreach (var template in templates) { var extension = template.Extension; string outputFile = Path.ChangeExtension(item.ModelFile, extension); string outputPath = Path.Combine(outputDirectory ?? string.Empty, outputFile); var dir = Path.GetDirectoryName(outputPath); if (!string.IsNullOrEmpty(dir)) { Directory.CreateDirectory(dir); } string transformed; if (model == null) { // TODO: remove // currently keep to pass UT transformed = template.Transform(item.ModelFile, systemAttrs); } else { var result = template.TransformModel(model, systemAttrs); if (exportMetadata) { if (metadataFilePathProvider == null) { throw new ArgumentNullException(nameof(metadataFilePathProvider)); } JsonUtility.Serialize(metadataFilePathProvider(outputPath), result.Model); } transformed = result.Result; } if (!string.IsNullOrWhiteSpace(transformed)) { if (extension.Equals(".html", StringComparison.OrdinalIgnoreCase)) { TranformHtml(context, transformed, item.ModelFile, outputPath); } else { File.WriteAllText(outputPath, transformed, Encoding.UTF8); } Logger.Log(LogLevel.Verbose, $"Transformed model \"{item.ModelFile}\" to \"{outputPath}\"."); } else { // TODO: WHAT to do if is transformed to empty string? STILL creat empty file? Logger.LogWarning($"Model \"{item.ModelFile}\" is transformed to empty string with template \"{template.Name}\""); File.WriteAllText(outputPath, string.Empty); } manifestItem.OutputFiles.Add(extension, outputFile); } } // 2. process resource if (item.ResourceFile != null) { PathUtility.CopyFile(Path.Combine(baseDirectory, item.ResourceFile), Path.Combine(outputDirectory, item.ResourceFile), true); manifestItem.OutputFiles.Add("resource", item.ResourceFile); } } catch (Exception e) { Logger.LogWarning($"Unable to transform {item.ModelFile}: {e.Message}. Ignored."); } return(manifestItem); }
private static void ProcessTemplate(string templateName, string inputFolder, IEnumerable<InternalManifestItem> items, object model, string outputFolder, params Tuple<string, string>[] templateFiles) { var rootTemplateFolder = "tmpl"; var templateFolder = Path.Combine(rootTemplateFolder, templateName); if (Directory.Exists(templateFolder)) Directory.Delete(templateFolder, true); WriteTemplate(templateFolder, templateFiles); using (var resource = new ResourceFinder(null, null).Find(templateFolder)) { var processor = new TemplateProcessor(resource, null, 4); var context = new DocumentBuildContext(inputFolder); foreach (var item in items) { if (item.ResourceFile != null) { var dir = Path.GetDirectoryName(item.ResourceFile); if (!string.IsNullOrEmpty(dir)) Directory.CreateDirectory(dir); File.Create(item.ResourceFile).Dispose(); } if (string.IsNullOrEmpty(item.InputFolder)) item.InputFolder = Directory.GetCurrentDirectory(); item.Model = new DocAsCode.Plugins.ModelWithCache(model); } var settings = new ApplyTemplateSettings(inputFolder, outputFolder); processor.Process(items.ToList(), context, settings); } }
public static List <TemplateManifestItem> Transform(TemplateProcessor processor, List <ManifestItem> manifest, DocumentBuildContext context, ApplyTemplateSettings settings) { if (settings.Options == ApplyTemplateOptions.ExportRawModel || processor == null) { ExportRawModel(manifest, settings); return(null); } using (new LoggerPhaseScope("Apply Templates")) { Logger.LogInfo($"Applying templates to {manifest.Count} model(s)..."); processor.ProcessDependencies(settings.OutputFolder); if (processor.IsEmpty) { Logger.LogWarning("No template is found."); ExportRawModel(manifest, settings); return(null); } Logger.LogVerbose("Start applying template..."); var outputDirectory = context.BuildOutputFolder; var templateManifest = processor.Transform(manifest, context, settings); if (!settings.Options.HasFlag(ApplyTemplateOptions.TransformDocument)) { Logger.LogInfo("Dryrun, no template will be applied to the documents."); } if (templateManifest.Count > 0) { // Save manifest from template var manifestPath = Path.Combine(outputDirectory ?? string.Empty, ManifestFileName); JsonUtility.Serialize(manifestPath, templateManifest); Logger.LogInfo($"Manifest file saved to {manifestPath}."); } return(templateManifest); } }