/// <summary> /// Generates the HTML result for a single source file. /// </summary> /// <param name="sourceFile"></param> /// <param name="docsDirectory"></param> /// <param name="job"></param> /// <returns>Generated document FileInfo</returns> private static DocumentSummary GenerateDocumentHtml(FileInfo sourceFile, DirectoryInfo docsDirectory, NoccoJob job, IEnumerable<FileInfo> othersInSameJob) { DocumentSummary summary = new DocumentSummary() { DocumentFile = sourceFile }; var destinationFile = GetAbsoluteDocDestination(sourceFile, docsDirectory, job.JobBaseDirectory); //the relative path from the destination file to the documation folder string docsRelative = Helpers.GetPathRelativeTo(destinationFile.Directory, docsDirectory); //get the opposite direction for the index page summary.RelativeUri = Helpers.ConvertPathSeparator(Path.Combine( Helpers.GetPathRelativeTo(docsDirectory, destinationFile.Directory), destinationFile.Name)); AbDocumentTemplate TemplateGenerator = Helpers.GetTemplateGenerator<AbDocumentTemplate>( new FileInfo(App.ResolveDirectory(App.Settings.DocumentTemplateFile))); //setup template generator settings TemplateGenerator.Title = sourceFile.Name; summary.Title = TemplateGenerator.Title; if (job.GenerateInlineIndex) { //list of other files in this same job, relative to myself TemplateGenerator.OtherDocumentsInJob = othersInSameJob.DefaultIfEmpty() .Select(o => { var abs = GetAbsoluteDocDestination(o, docsDirectory, job.JobBaseDirectory); return Path.Combine(Helpers.GetPathRelativeTo(destinationFile.Directory, abs.Directory), abs.Name); }) .ToArray(); } TemplateGenerator.Sections = ParseSections(sourceFile, job.Language, summary); TemplateGenerator.DocsRelative = docsRelative; if (job.GenerateIndexFile) { TemplateGenerator.IndexFile = Helpers.ConvertPathSeparator(Path.Combine(docsRelative, job.IndexFilename)); } //generate documenation file TemplateGenerator.Generate(destinationFile.FullName); return summary; }
/// <summary> /// Create separated and formatted sections for comments and code for use in documenation file /// </summary> /// <param name="source"></param> /// <param name="language"></param> /// <returns></returns> private static IEnumerable<Section> ParseSections(FileInfo source, LanguageConfig language, DocumentSummary summary) { var sections = new List<Section>(); var hasCode = false; var docsText = new StringBuilder(); var codeText = new StringBuilder(); bool OkayToReplaceSection = true; //generates a section of comment and code Func<StringBuilder, StringBuilder, Section> GenerateSection = (docs, code) => { var docsString = docs.ToString(); //highlight comments if required if (language.MarkdownMaps != null) { docsString = language.MarkdownMaps.Aggregate(docsString, (currentDocs, map) => Regex.Replace(currentDocs, map.FindPattern, map.Replacement, RegexOptions.Multiline) ); } var ret = new Section { DocsHtml = MarkdownFormatter.Transform(docsString), CodeHtml = System.Web.HttpUtility.HtmlEncode(code.ToString()) }; //set the top section for the summary, just in case, but ideally we want the second block //or a block after the first which has both sections if (summary.TopSection == null) { //easy winner summary.TopSection = ret; } else if (OkayToReplaceSection) { summary.TopSection = ret; OkayToReplaceSection = false; } else { if (string.IsNullOrWhiteSpace(summary.TopSection.CodeHtml) || string.IsNullOrWhiteSpace(summary.TopSection.DocsHtml)) { if (!string.IsNullOrWhiteSpace(ret.CodeHtml) && !string.IsNullOrWhiteSpace(ret.DocsHtml)) { //winner by content superiority summary.TopSection = ret; } } } return ret; }; foreach (var result in Parser.Process(source, language.CommentDefinitions)) { //if this line matches a comment line if (result.ResultType == ResultType.Comment) { //if we hit this comment line after already processing code, we need to make a new section if (hasCode) { yield return GenerateSection(docsText, codeText); hasCode = false; docsText = new StringBuilder(); codeText = new StringBuilder(); } //update the summary summary.LinesOfComment++; docsText.AppendLine(result.MatchingDefinition.CleanComment(result.Result)); } else //hit code or unknown line { //update the summary summary.LinesOfCode++; hasCode = true; codeText.AppendLine(result.Result); } } yield return GenerateSection(docsText, codeText); }