├── .gitattributes ├── .gitignore ├── CONTRIB.txt ├── LICENSE.txt ├── PxtlCa.XmlCommentMarkDownGenerator.MSBuild ├── BuildMessageWarningLogger.cs ├── CrudeNaturalSort.cs ├── GenerateMarkdown.cs ├── Model │ ├── SourceDocument.cs │ ├── TransformationInput.cs │ └── YamlOptions.cs ├── Properties │ └── AssemblyInfo.cs ├── PxtlCa.XmlCommentMarkDownGenerator.MSBuild.csproj └── packages.config ├── PxtlCa.XmlCommentMarkDownGenerator.Test ├── ElementC_input.xml ├── ElementPara_input.xml ├── ElementParam_input.xml ├── ElementTests.cs ├── Properties │ └── AssemblyInfo.cs ├── PxtlCa.XmlCommentMarkDownGenerator.Test.csproj ├── Regression.cs ├── RegressionBigVariant_input.xml ├── RegressionBigVariant_output.md ├── UnexpectedElement.cs ├── UnexpectedElement_input.xml └── Util │ ├── Helper.cs │ └── TestWarningLogger.cs ├── PxtlCa.XmlCommentMarkDownGenerator.nuspec ├── PxtlCa.XmlCommentMarkDownGenerator.targets ├── PxtlCa.XmlCommentMarkDownGenerator ├── App.config ├── ConversionContext.cs ├── IWarningLogger.cs ├── Options.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── PxtlCa.XmlCommentMarkDownGenerator.csproj ├── TagRenderers.cs ├── UnexpectedTagActionEnum.cs ├── XmlToMarkDown.cs └── packages.config ├── PxtlCa.XmlCommentMarkdownGenerator.MSBuild.Test ├── BuildEngine.cs ├── Properties │ └── AssemblyInfo.cs ├── PxtlCa.XmlCommentMarkdownGenerator.MSBuild.Test.csproj └── packages.config ├── README.md └── XmlCommentMarkDownGenerator.sln /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.azurePubxml 142 | # TODO: Comment the next line if you want to checkin your web deploy settings 143 | # but database connection strings (with potential passwords) will be unencrypted 144 | *.pubxml 145 | *.publishproj 146 | 147 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 148 | # checkin your Azure Web App publish settings, but sensitive information contained 149 | # in these scripts will be unencrypted 150 | PublishScripts/ 151 | 152 | # NuGet Packages 153 | *.nupkg 154 | # The packages folder can be ignored because of Package Restore 155 | **/packages/* 156 | # except build/, which is used as an MSBuild target. 157 | !**/packages/build/ 158 | # Uncomment if necessary however generally it will be regenerated when needed 159 | #!**/packages/repositories.config 160 | # NuGet v3's project.json files produces more ignoreable files 161 | *.nuget.props 162 | *.nuget.targets 163 | 164 | # Microsoft Azure Build Output 165 | csx/ 166 | *.build.csdef 167 | 168 | # Microsoft Azure Emulator 169 | ecf/ 170 | rcf/ 171 | 172 | # Windows Store app package directories and files 173 | AppPackages/ 174 | BundleArtifacts/ 175 | Package.StoreAssociation.xml 176 | _pkginfo.txt 177 | 178 | # Visual Studio cache files 179 | # files ending in .cache can be ignored 180 | *.[Cc]ache 181 | # but keep track of directories ending in .cache 182 | !*.[Cc]ache/ 183 | 184 | # Others 185 | ClientBin/ 186 | ~$* 187 | *~ 188 | *.dbmdl 189 | *.dbproj.schemaview 190 | *.pfx 191 | *.publishsettings 192 | node_modules/ 193 | orleans.codegen.cs 194 | 195 | # Since there are multiple workflows, uncomment next line to ignore bower_components 196 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 197 | #bower_components/ 198 | 199 | # RIA/Silverlight projects 200 | Generated_Code/ 201 | 202 | # Backup & report files from converting an old project file 203 | # to a newer Visual Studio version. Backup files are not needed, 204 | # because we have git ;-) 205 | _UpgradeReport_Files/ 206 | Backup*/ 207 | UpgradeLog*.XML 208 | UpgradeLog*.htm 209 | 210 | # SQL Server files 211 | *.mdf 212 | *.ldf 213 | 214 | # Business Intelligence projects 215 | *.rdl.data 216 | *.bim.layout 217 | *.bim_*.settings 218 | 219 | # Microsoft Fakes 220 | FakesAssemblies/ 221 | 222 | # GhostDoc plugin setting file 223 | *.GhostDoc.xml 224 | 225 | # Node.js Tools for Visual Studio 226 | .ntvs_analysis.dat 227 | 228 | # Visual Studio 6 build log 229 | *.plg 230 | 231 | # Visual Studio 6 workspace options file 232 | *.opt 233 | 234 | # Visual Studio LightSwitch build output 235 | **/*.HTMLClient/GeneratedArtifacts 236 | **/*.DesktopClient/GeneratedArtifacts 237 | **/*.DesktopClient/ModelManifest.xml 238 | **/*.Server/GeneratedArtifacts 239 | **/*.Server/ModelManifest.xml 240 | _Pvt_Extensions 241 | 242 | # Paket dependency manager 243 | .paket/paket.exe 244 | paket-files/ 245 | 246 | # FAKE - F# Make 247 | .fake/ 248 | 249 | # JetBrains Rider 250 | .idea/ 251 | *.sln.iml 252 | 253 | # SSDT artifacts 254 | Model.xml 255 | *.FileListAbsolute.txt 256 | PxtlCa.XmlCommentMarkDownGenerator.MSBuild.Test/Readme.md 257 | PxtlCa.XmlCommentMarkDownGenerator.MSBuild.Test/Docs/PxtlCa.XmlCommentMarkDownGenerator.MSBuild_altered.md 258 | PxtlCa.XmlCommentMarkDownGenerator.MSBuild.Test/Docs/PxtlCa.XmlCommentMarkDownGenerator.MSBuild.md 259 | -------------------------------------------------------------------------------- /CONTRIB.txt: -------------------------------------------------------------------------------- 1 | Contributing 2 | This is a side-project by Martin Zarate (aka Pxtl), and so any contributions in the form 3 | of bug reports and fixes are appreciated. Realistically, as a side-project with very 4 | limited developer hours, the most effective way to fix a bug is to develop a fix yourself 5 | and pull-request it into the project for others to use. 6 | 7 | Issues 8 | 9 | Bugs or anomalies in the behavior of this program, issues with its installation, requests 10 | for changes in documentation, design and development issues, and feature requests will 11 | be tracked via GitHub's Issues mechanism. 12 | 13 | When reporting a bug, please provide the following info if appropriate: 14 | What are the steps to reproduce the bug? If possible, the simplest such set of steps 15 | is best. 16 | Does the bug still happen using the latest version? 17 | What PxtlCa.XmlCommentMarkDownGenerator version and OS are you using? 18 | 19 | Submitting a Pull Request 20 | 21 | Pull Requests are welcome, however code-quality will be maintained. While project grew 22 | out of a code snippet that used a somewhat unusual pattern and code quality is as such 23 | somewhat low, it will not be allowed to get worse. Code will be nitpicked, and large 24 | rewrites or huge features dumped in all at once will likely be blocked. 25 | 26 | License 27 | 28 | PxtlCa.XmlCommentMarkDownGenerator is licensed under the terms in LICENSE. 29 | By contributing to the project, you agree to the terms of the license and to release your 30 | contribution under those terms. -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Martin Zarate 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.MSBuild/BuildMessageWarningLogger.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Build.Utilities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace PxtlCa.XmlCommentMarkDownGenerator.MSBuild 9 | { 10 | internal class BuildMessageWarningLogger : IWarningLogger 11 | { 12 | private TaskLoggingHelper _log; 13 | internal BuildMessageWarningLogger(TaskLoggingHelper log) { _log = log; } 14 | 15 | public void LogWarning(string warning) 16 | { 17 | _log.LogWarning(warning); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.MSBuild/CrudeNaturalSort.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PxtlCa.XmlCommentMarkDownGenerator.MSBuild 8 | { 9 | public class CrudeNaturalSort : IComparer 10 | { 11 | public static CrudeNaturalSort Instance {get;} = new CrudeNaturalSort(); 12 | 13 | public int Compare(string x, string y) 14 | { 15 | return int.TryParse(x, out int ix) && int.TryParse(y, out int iy) 16 | ? ix.CompareTo(iy) 17 | : string.Compare(x, y); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.MSBuild/GenerateMarkdown.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | //using System.Threading.Tasks; 6 | using Microsoft.Build.Framework; 7 | using Microsoft.Build.Utilities; 8 | using System.IO; 9 | using System.Xml.Linq; 10 | using System.Xml; 11 | using YamlDotNet.Serialization; 12 | using YamlDotNet.Serialization.NamingConventions; 13 | using PxtlCa.XmlCommentMarkDownGenerator.MSBuild.Options; 14 | using System.Text.RegularExpressions; 15 | 16 | namespace PxtlCa.XmlCommentMarkDownGenerator.MSBuild 17 | { 18 | /// 19 | /// A task that generates and optionally merges markdown 20 | /// 21 | public class GenerateMarkdown : Task 22 | { 23 | /// 24 | /// The file(s) from which to generate markdown. This should be in XmlDocumentation format. 25 | /// 26 | [Required] 27 | public ITaskItem[] InputXml { get; set; } 28 | 29 | /// 30 | /// DocumentationPath is the top level directory in which 31 | /// generated markdown files are created. 32 | /// 33 | [Required] 34 | public ITaskItem TargetDocumentDirPath { get; set; } 35 | 36 | /// 37 | /// SourceDocumentDirPath is the top level directory in which to search for markdown files. 38 | /// 39 | [Required] 40 | public ITaskItem SourceDocumentDirPath { get; set; } 41 | 42 | /// 43 | /// Defaults to Error. Event to execute when an unexpected tag is found. 44 | /// 45 | public UnexpectedTagActionEnum UnexpectedTagAction { get; set; } = UnexpectedTagActionEnum.Error; 46 | 47 | /// 48 | /// Runs the task as configured 49 | /// 50 | /// true if task has succeeded 51 | public override bool Execute() 52 | { 53 | if (InputXml.Length == 0) 54 | { 55 | Log.LogError($"{nameof(InputXml)} cannot be empty."); 56 | return false; 57 | } 58 | 59 | if (File.Exists(TargetDocumentDirPath.ItemSpec)) 60 | { 61 | Log.LogError($"{nameof(TargetDocumentDirPath)} must be a directory, not a file."); 62 | return false; 63 | } 64 | 65 | if (File.Exists(SourceDocumentDirPath.ItemSpec)) 66 | { 67 | Log.LogError($"{nameof(SourceDocumentDirPath)} must be a directory, not a file."); 68 | return false; 69 | } 70 | 71 | if (!Directory.Exists(SourceDocumentDirPath.ItemSpec)) 72 | { 73 | Log.LogError($"{nameof(SourceDocumentDirPath)} directory does not exist."); 74 | return false; 75 | } 76 | 77 | var markdownSourceDocuments = Directory.EnumerateFiles(SourceDocumentDirPath.ItemSpec, "*.md") 78 | .Select(f => GetSourceDocument(f)) 79 | .ToList(); 80 | 81 | //try for several sources of header data 82 | IEnumerable sourceDocumentsToExecute = null; 83 | //check for YAML-header files 84 | var sourceDocsWithYaml = markdownSourceDocuments.Where(doc => 85 | doc.Options != null 86 | ); 87 | if (sourceDocsWithYaml.Count() > 0) 88 | { 89 | sourceDocumentsToExecute = sourceDocsWithYaml.Select(src 90 | => new TransformationInput() { SourceDocument = src, InputXml = InputXml } 91 | ); 92 | } 93 | 94 | if (sourceDocumentsToExecute == null) 95 | { 96 | //try check Readme file 97 | var readmeSourceDocument = markdownSourceDocuments.SingleOrDefault(src => 98 | Path.GetFileNameWithoutExtension(src.FileName) 99 | .Equals("Readme", StringComparison.OrdinalIgnoreCase) 100 | ); 101 | if (readmeSourceDocument != null) 102 | { 103 | sourceDocumentsToExecute = new[] { 104 | new TransformationInput() { SourceDocument = readmeSourceDocument, InputXml = InputXml } 105 | }; 106 | } 107 | } 108 | 109 | if (sourceDocumentsToExecute == null) 110 | { 111 | //try check for filename match 112 | var matchedNameInputs = markdownSourceDocuments.Join( 113 | InputXml, 114 | src => Path.GetFileNameWithoutExtension(src.FileName), 115 | xml => Path.GetFileNameWithoutExtension(xml.ItemSpec), 116 | (src, xml) => new TransformationInput() { SourceDocument = src, InputXml = new[] { xml } } 117 | ); 118 | if (matchedNameInputs.Count() > 0) 119 | { 120 | sourceDocumentsToExecute = matchedNameInputs; 121 | } 122 | } 123 | 124 | if (sourceDocumentsToExecute == null) 125 | { 126 | //try create dummies source file, use matching name to xml file 127 | sourceDocumentsToExecute = InputXml.Select(xml => new TransformationInput() 128 | { 129 | InputXml = new[] { xml }, 130 | SourceDocument = new SourceDocument() 131 | { 132 | Body = string.Empty, 133 | Options = null, 134 | FileName = Path.GetFileNameWithoutExtension(xml.ItemSpec) 135 | } 136 | }); 137 | } 138 | 139 | try 140 | { 141 | GenerateFiles(sourceDocumentsToExecute); 142 | return true; 143 | } 144 | catch (Exception ex) 145 | { 146 | LoggedException = ex; 147 | Log.LogErrorFromException(ex); 148 | } 149 | return false; 150 | } 151 | 152 | /// 153 | /// Load a Markdown file and parse out its Yaml header if any, building a SourceDocument object 154 | /// 155 | /// A Markdown file with a PanDoc-style YAML header. 156 | /// A SourceDocument object. Options is null 157 | public SourceDocument GetSourceDocument(string fileName) 158 | { 159 | GetFileSections(fileName, out string frontMatter, out string body); 160 | return new SourceDocument() 161 | { 162 | Options = ReadOptionsFromString(frontMatter), 163 | FileName = fileName, 164 | Body = body 165 | }; 166 | } 167 | 168 | /// 169 | /// Use this to handle front matter in markdown files 170 | /// 171 | /// the path to the file 172 | /// the front matter found. Empty string if missing or trivial. 173 | /// the body of the source document 174 | /// true if front matter indicator(s) are found 175 | public static void GetFileSections(string filePath, out string frontMatter, out string body) 176 | { 177 | var lines = File.ReadLines(filePath); 178 | var firstLine = lines.FirstOrDefault() ?? string.Empty; 179 | var yamlLinesCount = 0; 180 | 181 | if (firstLine.StartsWith("---")) //yaml start 182 | { 183 | var yamlSB = new StringBuilder(); 184 | yamlLinesCount = 1; 185 | foreach (var line in lines) 186 | { 187 | if (line.StartsWith("---") && yamlLinesCount > 1) 188 | { 189 | break; 190 | } 191 | yamlSB.AppendLine(line); 192 | yamlLinesCount += 1; 193 | } 194 | 195 | frontMatter = yamlSB.ToString(); 196 | } 197 | else 198 | { 199 | frontMatter = string.Empty; 200 | } 201 | body = String.Join(Environment.NewLine, lines.Skip(yamlLinesCount)); 202 | } 203 | 204 | private static readonly Regex EmptyFrontMatterRegex 205 | = new Regex(@"---\s+"); 206 | private YamlOptions ReadOptionsFromString(string frontMatter) 207 | { 208 | //HACK: Yaml deserializer continues a simple ---\r\n\ to *not* be a valid YAML doc. 209 | //we want to consider that a valid YAML doc. 210 | if(EmptyFrontMatterRegex.IsMatch(frontMatter)) 211 | { 212 | return new YamlOptions(); 213 | } 214 | 215 | var input = new StringReader(frontMatter); 216 | var deserializer = new DeserializerBuilder() 217 | .WithNamingConvention(new CamelCaseNamingConvention()) 218 | .IgnoreUnmatchedProperties() 219 | .Build(); 220 | var options = deserializer.Deserialize(input); 221 | return options; 222 | } 223 | 224 | /// 225 | /// for testing. 226 | /// sets the exception for throw outside the catch 227 | /// 228 | public Exception LoggedException { get; set; } 229 | 230 | private void GenerateFiles(IEnumerable inputs) 231 | { 232 | var groupedInputs = inputs.GroupBy(input => input.RelativeOutputPath, StringComparer.OrdinalIgnoreCase); 233 | 234 | foreach (var inputGroup in groupedInputs) 235 | { 236 | var relativeOutputPath = inputGroup.Key; 237 | var fullOutputPath = Path.Combine(TargetDocumentDirPath.ItemSpec, relativeOutputPath); 238 | Directory.CreateDirectory(Path.GetDirectoryName(fullOutputPath)); 239 | 240 | var inputsForOutput = inputGroup.OrderBy(i => i.MergeSequence, CrudeNaturalSort.Instance); 241 | using (var sw = new StreamWriter(fullOutputPath)) 242 | { 243 | foreach (var input in inputsForOutput) 244 | { 245 | sw.WriteLine(input.SourceDocument.Body); 246 | foreach (var inputXml in input.InputXml) 247 | { 248 | var context = new ConversionContext() { 249 | AssemblyName = Path.GetFileNameWithoutExtension(inputXml.ItemSpec), 250 | UnexpectedTagAction = UnexpectedTagAction, 251 | WarningLogger = new BuildMessageWarningLogger(Log) 252 | }; 253 | 254 | using (var sr = new StreamReader(inputXml.ItemSpec)) 255 | { 256 | var xml = sr.ReadToEnd(); 257 | var doc = XDocument.Parse(xml); 258 | var md = doc.Root.ToMarkDown(context); 259 | sw.WriteLine(md); 260 | } 261 | } 262 | } 263 | } 264 | } 265 | } 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.MSBuild/Model/SourceDocument.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace PxtlCa.XmlCommentMarkDownGenerator.MSBuild.Options 9 | { 10 | public class SourceDocument 11 | { 12 | public YamlOptions Options { get; set; } 13 | public string FileName { get; set; } 14 | public string Body { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.MSBuild/Model/TransformationInput.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Build.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace PxtlCa.XmlCommentMarkDownGenerator.MSBuild.Options 10 | { 11 | public class TransformationInput 12 | { 13 | public SourceDocument SourceDocument { get; set; } 14 | public IEnumerable InputXml { get; set; } 15 | 16 | public string RelativeOutputPath 17 | { 18 | get 19 | { 20 | return this.SourceDocument.Options?.OutputFile 21 | ?? $"{Path.GetFileNameWithoutExtension(this.SourceDocument.FileName)}.md"; 22 | } 23 | } 24 | 25 | public string MergeSequence 26 | { 27 | get 28 | { 29 | return (this.SourceDocument.Options == null) 30 | ? Path.GetFileName(this.RelativeOutputPath) 31 | : Convert.ToString(SourceDocument.Options.MergeSequence); 32 | } 33 | } 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.MSBuild/Model/YamlOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using YamlDotNet.Serialization; 7 | 8 | namespace PxtlCa.XmlCommentMarkDownGenerator.MSBuild.Options 9 | { 10 | /// 11 | /// The options to be deserialized from the front matter found. 12 | /// 13 | public class YamlOptions 14 | { 15 | [YamlMember(Alias = nameof(UnexpectedTagAction), ApplyNamingConventions = false)] 16 | public string UnexpectedTagAction { get; set; } 17 | 18 | [YamlMember(Alias = nameof(MergeSequence), ApplyNamingConventions = false)] 19 | public int MergeSequence { get; set; } 20 | 21 | //[YamlMember(Alias = nameof(AssemblyNames), ApplyNamingConventions = false)] 22 | //public string AssemblyNames { get; set; } 23 | 24 | [YamlIgnore] 25 | public UnexpectedTagActionEnum UnexpectedTagActionAsEnum 26 | { 27 | get 28 | { 29 | if (Enum.TryParse(UnexpectedTagAction, true, 30 | out UnexpectedTagActionEnum result)) 31 | { 32 | return result; 33 | } 34 | else 35 | { 36 | return UnexpectedTagActionEnum.Error; 37 | } 38 | } 39 | } 40 | 41 | //[YamlMember(Alias = "Namespaces", ApplyNamingConventions = false)] 42 | //public string Namespaces { get; set; } 43 | [YamlMember(Alias = nameof(OutputFile), ApplyNamingConventions = false)] 44 | public string OutputFile { get; set; } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.MSBuild/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("PxtlCa.XmlCommentMarkDownGenerator.MSBuild")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("PxtlCa.XmlCommentMarkDownGenerator.MSBuild")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("9fcee209-508f-474e-80c2-d0966e4aa126")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("0.3.*")] 36 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.MSBuild/PxtlCa.XmlCommentMarkDownGenerator.MSBuild.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {9FCEE209-508F-474E-80C2-D0966E4AA126} 8 | Library 9 | Properties 10 | PxtlCa.XmlCommentMarkDownGenerator.MSBuild 11 | PxtlCa.XmlCommentMarkDownGenerator.MSBuild 12 | v4.5.2 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | bin\Debug\PxtlCa.XmlCommentMarkDownGenerator.MSBuild.xml 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | ..\packages\YamlDotNet.4.2.2\lib\net35\YamlDotNet.dll 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | {1375dc94-03f8-496c-981c-d5d6e1b0fd26} 61 | PxtlCa.XmlCommentMarkDownGenerator 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.MSBuild/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.Test/ElementC_input.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | PxtlCa.TestAssembly 5 | 6 | 7 | 8 | 9 | This example involves the code tag c, does it work? 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.Test/ElementPara_input.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | PxtlCa.TestAssembly 5 | 6 | 7 | 8 | 9 | first paragraph 10 | second paragraph 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.Test/ElementParam_input.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | PxtlCa.TestAssembly 5 | 6 | 7 | 8 | 9 | parameter test type summary 10 | 11 | 12 | 13 | 14 | parameter test method 15 | 16 | object A foo 17 | object B bar 18 | object C baz 19 | 20 | 21 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.Test/ElementTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using PxtlCa.XmlCommentMarkDownGenerator.Test.Util; 3 | using System.Text.RegularExpressions; 4 | 5 | namespace PxtlCa.XmlCommentMarkDownGenerator.Test 6 | { 7 | /// 8 | /// Summary description for ElementTests 9 | /// 10 | [TestClass] 11 | public class ElementTests 12 | { 13 | public ElementTests() 14 | { 15 | 16 | } 17 | 18 | private TestContext testContextInstance; 19 | 20 | /// 21 | ///Gets or sets the test context which provides 22 | ///information about and functionality for the current test run. 23 | /// 24 | public TestContext TestContext 25 | { 26 | get 27 | { 28 | return testContextInstance; 29 | } 30 | set 31 | { 32 | testContextInstance = value; 33 | } 34 | } 35 | 36 | #region Additional test attributes 37 | // 38 | // You can use the following additional attributes as you write your tests: 39 | // 40 | // Use ClassInitialize to run code before running the first test in the class 41 | // [ClassInitialize()] 42 | // public static void MyClassInitialize(TestContext testContext) { } 43 | // 44 | // Use ClassCleanup to run code after all tests in a class have run 45 | // [ClassCleanup()] 46 | // public static void MyClassCleanup() { } 47 | // 48 | // Use TestInitialize to run code before running each test 49 | // [TestInitialize()] 50 | // public void MyTestInitialize() { } 51 | // 52 | // Use TestCleanup to run code after each test has run 53 | // [TestCleanup()] 54 | // public void MyTestCleanup() { } 55 | // 56 | #endregion 57 | 58 | [TestMethod] 59 | public void ElementPara() 60 | { 61 | var inputResourceName = "PxtlCa.XmlCommentMarkDownGenerator.Test.ElementPara_input.xml"; 62 | Regex normalizeSpace = new Regex(@"\s+", RegexOptions.Compiled); 63 | var testInput = Helper.FetchResourceAsString(inputResourceName); 64 | 65 | var testOutput = normalizeSpace.Replace(testInput.ToMarkDown(), " "); 66 | //TODO: better test here 67 | } 68 | 69 | [TestMethod] 70 | public void ElementC() 71 | { 72 | var inputResourceName = "PxtlCa.XmlCommentMarkDownGenerator.Test.ElementC_input.xml"; 73 | Regex normalizeSpace = new Regex(@"\s+", RegexOptions.Compiled); 74 | var testInput = Helper.FetchResourceAsString(inputResourceName); 75 | 76 | var testOutput = normalizeSpace.Replace(testInput.ToMarkDown(), " "); 77 | Assert.IsTrue(testOutput.Contains("`code tag c`")); 78 | } 79 | 80 | [TestMethod] 81 | public void ElementParam() 82 | { 83 | var inputResourceName = "PxtlCa.XmlCommentMarkDownGenerator.Test.ElementParam_input.xml"; 84 | Regex normalizeSpace = new Regex(@"\s+", RegexOptions.Compiled); 85 | var testInput = Helper.FetchResourceAsString(inputResourceName); 86 | 87 | var testOutput = normalizeSpace.Replace(testInput.ToMarkDown(), " "); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.Test/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("PxtlCa.XmlCommentMarkDownGenerator.Test")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("PxtlCa.XmlCommentMarkDownGenerator.Test")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("7993d07f-7f81-477e-aba1-e3e6dc5cab6a")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.Test/PxtlCa.XmlCommentMarkDownGenerator.Test.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {7993D07F-7F81-477E-ABA1-E3E6DC5CAB6A} 7 | Library 8 | Properties 9 | PxtlCa.XmlCommentMarkDownGenerator.Test 10 | PxtlCa.XmlCommentMarkDownGenerator.Test 11 | v4.5.2 12 | 512 13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 10.0 15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 17 | False 18 | UnitTest 19 | 20 | 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | False 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | {1375dc94-03f8-496c-981c-d5d6e1b0fd26} 73 | PxtlCa.XmlCommentMarkDownGenerator 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | False 93 | 94 | 95 | False 96 | 97 | 98 | False 99 | 100 | 101 | False 102 | 103 | 104 | 105 | 106 | 107 | 108 | 115 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.Test/Regression.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using PxtlCa.XmlCommentMarkDownGenerator.Test.Util; 3 | using System.Linq; 4 | using System.Text.RegularExpressions; 5 | 6 | namespace PxtlCa.XmlCommentMarkDownGenerator.Test 7 | { 8 | [TestClass] 9 | public class Regression 10 | { 11 | [TestMethod] 12 | public void TestBigVariantXml() 13 | { 14 | var testInput = Helper.GetRegressionTestXml(); 15 | var outputResourceName = "PxtlCa.XmlCommentMarkDownGenerator.Test.RegressionBigVariant_output.md"; 16 | Regex normalizeSpace = new Regex(@"\s+", RegexOptions.Compiled); 17 | 18 | var expectedOutput = normalizeSpace.Replace(Helper.FetchResourceAsString(outputResourceName), " "); 19 | var actualOutput = normalizeSpace.Replace(testInput.ToMarkDown(), " "); 20 | Assert.AreEqual(expectedOutput, actualOutput); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.Test/RegressionBigVariant_input.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PxtlCa.BigVariant.Core 5 | 6 | 7 | 8 | 9 | The SQLCLR BigVariant type 10 | 11 | 12 | 13 | 14 | The SQL CLR Type of the BigVariant, as a String accessible from SQL. 15 | See https://msdn.microsoft.com/en-us/library/ms131092.aspx for information about the types. 16 | 17 | 18 | DECLARE @testInput bit = 1 19 | DECLARE @testVar BigVariant = dbo.BigVariantFromVariant(@testInput) 20 | SELECT @testVar.Type -- returns 'SqlBoolean' 21 | 22 | 23 | 24 | 25 | If the BigVariant contains a SQL_VARIANT-compatible type, get its contents. 26 | Will throw an exception if the type is not SQL_VARIANT-compatible. 27 | 28 | DATETIME2s will be converted to DateTimes as interrim, use AsDateTime2 if you need DATETIME2s 29 | 30 | DECLARE @testInput float = 1.79E+308 31 | DECLARE @testVar BigVariant = dbo.BigVariantFromVariant(@testInput) 32 | SELECT @testVar.AsVariant 33 | -- returns 1.79E+308 34 | 35 | 36 | 37 | 38 | If the BigVariant contains a DATETIME2 (DateTime in CLR), get its contents. 39 | Will throw an exception if the type is not DATETIME2. 40 | 41 | 42 | DATETIME2 Unit Test 43 | 44 | DECLARE @testInput DateTime2 = convert(DateTime2, '0001-01-01 11:59:00 PM') 45 | DECLARE @testVar BigVariant = dbo.BigVariantFromDateTime2(@testInput) 46 | SELECT 'success' WHERE @testInput = @testVar.AsDateTime2 47 | 48 | 49 | 50 | 51 | If the BigVariant contains XML, get its contents. 52 | Will throw an exception if the type is not XML. 53 | 54 | 55 | Use xpath to pull data out of an Xml BigVariant. 56 | ' + CHAR(13)+CHAR(10) + CHAR(13)+CHAR(10) 59 | + 'Gambardella, MatthewXML Developer''s GuideComputer44.952000-10-01An in-depth look at creating applications with XML.' + CHAR(13)+CHAR(10) + CHAR(13)+CHAR(10) 60 | + '' + CHAR(13)+CHAR(10) + CHAR(13)+CHAR(10) 61 | ) 62 | DECLARE @testVar BigVariant = dbo.BigVariantFromXml(@testInput) 63 | SELECT @testVar.AsXml.Query('/catalog/book/author/text()') 64 | -- returns 'Gambardella, Matthew' as XML 65 | ]]> 66 | 67 | 68 | 69 | If the BigVariant contains NVARCHAR(MAX) or similar long SqlString object, get its contents. 70 | Will throw an exception if the type is not NVARCHAR(MAX) or similar long SqlString object. 71 | 72 | 73 | Unit test. 74 | 75 | DECLARE @testString NVARCHAR(2000) = 'Silence is foo' 76 | DECLARE @testVar BigVariant = dbo.BigVariantFromVariant(@testString) 77 | SELECT 'success' WHERE @testString = @testVar.AsString 78 | 79 | 80 | 81 | 82 | 83 | If the BigVariant contains VARBINARY(MAX) or similar long SqlBinary object, get its contents. 84 | Will throw an exception if the type is not VARBINARY(MAX) or similar long SqlBinary object. 85 | 86 | 87 | 88 | 89 | Implement IBinarySerialize.Read because SQL stores everything as binary even temporarily. Internal plumbing method, don't use. 90 | 91 | 92 | 93 | 94 | Implement IBinarySerialize.Write because SQL stores everything as binary even temporarily. Internal plumbing method, don't use. 95 | 96 | 97 | 98 | 99 | This class collects together various SQL User-Defined-functions used to construct BigVariant values out of various SQL types. 100 | 101 | 102 | 103 | 104 | Take the given XML typed SQL object and convert it into a BigVariant. 105 | 106 | an XML object to wrap in a BigVariant 107 | A BigVariant containing the given XML object 108 | ' + CHAR(13)+CHAR(10) + CHAR(13)+CHAR(10) 111 | + 'Gambardella, MatthewXML Developer''s GuideComputer44.952000-10-01An in-depth look at creating applications with XML.' + CHAR(13)+CHAR(10) + CHAR(13)+CHAR(10) 112 | + '' + CHAR(13)+CHAR(10) + CHAR(13)+CHAR(10) 113 | ) 114 | DECLARE @testVar BigVariant = dbo.BigVariantFromXml(@testInput) 115 | SELECT 'success' WHERE CONVERT(NVARCHAR(4000), @testInput) = CONVERT(NVARCHAR(4000), @testVar.AsXml) 116 | ]]> 117 | 118 | 119 | 120 | Take the given SQL_VARIANT object and convert it into a BigVariant. 121 | 122 | a SQL_VARIANT to wrap in a BigVariant 123 | A BigVariant containing the given SQL_VARIANT 124 | DateTime2s will be converted to DateTimes as intermediate, use BigVariantFromDateTime2 for proper datetime2. 125 | 126 | DECLARE @testInput float = 1.79E+308 127 | DECLARE @testVar BigVariant = dbo.BigVariantFromVariant(@testInput) 128 | SELECT @testVar.AsVariant 129 | -- returns 1.79E+308 130 | 131 | 132 | 133 | 134 | Take the given DATETIME2 object and convert it into a BigVariant. 135 | 136 | a DATETIME2 to wrap in a BigVariant 137 | A BigVariant containing the given DATETIME2 138 | 139 | 140 | 141 | Take the given NVARCHAR(MAX) or TEXT or NTEXT object and convert it into a BigVariant. 142 | 143 | an NVARCHAR(MAX) or TEXT or NTEXT to wrap in a BigVariant 144 | A BigVariant containing the given NVARCHAR(MAX) or TEXT or NTEXT 145 | 146 | DECLARE @testString NVARCHAR(MAX) 147 | DECLARE @testVar BigVariant 148 | SET @testString = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus.' + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) 149 | + 'Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum. Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc, quis gravida magna mi a libero. Fusce vulputate eleifend sapien. Vestibulum purus quam, scelerisque ut, mollis sed, nonummy id, metus. Nullam accumsan lorem in dui. Cras ultricies mi eu turpis hendrerit fringilla. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; In ac dui quis mi consectetuer lacinia. Nam pretium turpis et arcu. Duis arcu tortor, suscipit eget, imperdiet nec, imperdiet iaculis, ipsum.' + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) 150 | + 'Sed aliquam ultrices mauris. Integer ante arcu, accumsan a, consectetuer eget, posuere ut, mauris. Praesent adipiscing. Phasellus ullamcorper ipsum rutrum nunc. Nunc nonummy metus. Vestibulum volutpat pretium libero. Cras id dui. Aenean ut eros et nisl sagittis vestibulum. Nullam nulla eros, ultricies sit amet, nonummy id, imperdiet feugiat, pede. Sed lectus. Donec mollis hendrerit risus. Phasellus nec sem in justo pellentesque facilisis. Etiam imperdiet imperdiet orci. Nunc nec neque. Phasellus leo dolor, tempus non, auctor et, hendrerit quis, nisi. Curabitur ligula sapien, tincidunt non, euismod vitae, posuere imperdiet, leo. Maecenas malesuada. Praesent congue erat at massa. Sed cursus turpis vitae tortor. Donec posuere vulputate arcu. Phasellus accumsan cursus velit.' + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) 151 | SET @testVar = dbo.BigVariantFromString(@testString) 152 | 153 | 154 | 155 | 156 | Take the given VARBINARY(MAX) or IMAGE or other binary object and convert it into a BigVariant. 157 | 158 | an VARBINARY(MAX) or IMAGE or other binary to wrap in a BigVariant 159 | A BigVariant containing the given VARBINARY(MAX) or IMAGE or other binary 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.Test/RegressionBigVariant_output.md: -------------------------------------------------------------------------------- 1 | # PxtlCa.BigVariant.Core # 2 | 3 | ## Type BigVariant 4 | 5 | The SQLCLR BigVariant type 6 | 7 | --- 8 | #### Property BigVariant.Type 9 | 10 | The SQL CLR Type of the BigVariant, as a String accessible from SQL. See https://msdn.microsoft.com/en-us/library/ms131092.aspx for information about the types. 11 | 12 | ##### Example: 13 | 14 | ###### SQL code 15 | 16 | ``` 17 | DECLARE @testInput bit = 1 18 | DECLARE @testVar BigVariant = dbo.BigVariantFromVariant(@testInput) 19 | SELECT @testVar.Type -- returns 'SqlBoolean' 20 | ``` 21 | 22 | --- 23 | #### Property BigVariant.AsVariant 24 | 25 | If the BigVariant contains a SQL_VARIANT-compatible type, get its contents. Will throw an exception if the type is not SQL_VARIANT-compatible. 26 | 27 | >DATETIME2s will be converted to DateTimes as interrim, use AsDateTime2 if you need DATETIME2s 28 | 29 | ##### Example: 30 | 31 | ###### SQL code 32 | 33 | ``` 34 | DECLARE @testInput float = 1.79E+308 35 | DECLARE @testVar BigVariant = dbo.BigVariantFromVariant(@testInput) 36 | SELECT @testVar.AsVariant 37 | -- returns 1.79E+308 38 | ``` 39 | 40 | --- 41 | #### Property BigVariant.AsDateTime2 42 | 43 | If the BigVariant contains a DATETIME2 (DateTime in CLR), get its contents. Will throw an exception if the type is not DATETIME2. 44 | 45 | ##### Example: DATETIME2 Unit Test 46 | 47 | ###### SQL code 48 | 49 | ``` 50 | DECLARE @testInput DateTime2 = convert(DateTime2, '0001-01-01 11:59:00 PM') 51 | DECLARE @testVar BigVariant = dbo.BigVariantFromDateTime2(@testInput) 52 | SELECT 'success' WHERE @testInput = @testVar.AsDateTime2 53 | ``` 54 | 55 | --- 56 | #### Property BigVariant.AsXml 57 | 58 | If the BigVariant contains XML, get its contents. Will throw an exception if the type is not XML. 59 | 60 | ##### Example: Use xpath to pull data out of an Xml BigVariant. 61 | 62 | ###### SQL code 63 | 64 | ``` 65 | DECLARE @testInput Xml = convert(Xml 66 | , '' + CHAR(13)+CHAR(10) + CHAR(13)+CHAR(10) 67 | + 'Gambardella, MatthewXML Developer''s GuideComputer44.952000-10-01An in-depth look at creating applications with XML.' + CHAR(13)+CHAR(10) + CHAR(13)+CHAR(10) 68 | + '' + CHAR(13)+CHAR(10) + CHAR(13)+CHAR(10) 69 | ) 70 | DECLARE @testVar BigVariant = dbo.BigVariantFromXml(@testInput) 71 | SELECT @testVar.AsXml.Query('/catalog/book/author/text()') 72 | -- returns 'Gambardella, Matthew' as XML 73 | ``` 74 | 75 | --- 76 | #### Property BigVariant.AsString 77 | 78 | If the BigVariant contains NVARCHAR(MAX) or similar long SqlString object, get its contents. Will throw an exception if the type is not NVARCHAR(MAX) or similar long SqlString object. 79 | 80 | ##### Example: Unit test. 81 | 82 | ###### SQL code 83 | 84 | ``` 85 | DECLARE @testString NVARCHAR(2000) = 'Silence is foo' 86 | DECLARE @testVar BigVariant = dbo.BigVariantFromVariant(@testString) 87 | SELECT 'success' WHERE @testString = @testVar.AsString 88 | ``` 89 | 90 | --- 91 | #### Property BigVariant.AsBinary 92 | 93 | If the BigVariant contains VARBINARY(MAX) or similar long SqlBinary object, get its contents. Will throw an exception if the type is not VARBINARY(MAX) or similar long SqlBinary object. 94 | 95 | --- 96 | #### Method BigVariant.Read(System.IO.BinaryReader) 97 | 98 | Implement IBinarySerialize.Read because SQL stores everything as binary even temporarily. Internal plumbing method, don't use. 99 | 100 | --- 101 | #### Method BigVariant.Write(System.IO.BinaryWriter) 102 | 103 | Implement IBinarySerialize.Write because SQL stores everything as binary even temporarily. Internal plumbing method, don't use. 104 | 105 | --- 106 | ## Type UserDefinedFunctions 107 | 108 | This class collects together various SQL User-Defined-functions used to construct BigVariant values out of various SQL types. 109 | 110 | --- 111 | #### Method UserDefinedFunctions.BigVariantFromXml(System.Data.SqlTypes.SqlXml) 112 | 113 | Take the given XML typed SQL object and convert it into a BigVariant. 114 | 115 | |Name | Description | 116 | |-----|------| 117 | |value: |an XML object to wrap in a BigVariant| 118 | **Returns**: A BigVariant containing the given XML object 119 | 120 | ##### Example: 121 | 122 | ###### SQL code 123 | 124 | ``` 125 | DECLARE @testInput Xml = convert(Xml 126 | , '' + CHAR(13)+CHAR(10) + CHAR(13)+CHAR(10) 127 | + 'Gambardella, MatthewXML Developer''s GuideComputer44.952000-10-01An in-depth look at creating applications with XML.' + CHAR(13)+CHAR(10) + CHAR(13)+CHAR(10) 128 | + '' + CHAR(13)+CHAR(10) + CHAR(13)+CHAR(10) 129 | ) 130 | DECLARE @testVar BigVariant = dbo.BigVariantFromXml(@testInput) 131 | SELECT 'success' WHERE CONVERT(NVARCHAR(4000), @testInput) = CONVERT(NVARCHAR(4000), @testVar.AsXml) 132 | ``` 133 | 134 | --- 135 | #### Method UserDefinedFunctions.BigVariantFromVariant(System.Object) 136 | 137 | Take the given SQL_VARIANT object and convert it into a BigVariant. 138 | 139 | |Name | Description | 140 | |-----|------| 141 | |value: |a SQL_VARIANT to wrap in a BigVariant| 142 | **Returns**: A BigVariant containing the given SQL_VARIANT 143 | 144 | >DateTime2s will be converted to DateTimes as intermediate, use BigVariantFromDateTime2 for proper datetime2. 145 | 146 | ##### Example: 147 | 148 | ###### SQL code 149 | 150 | ``` 151 | DECLARE @testInput float = 1.79E+308 152 | DECLARE @testVar BigVariant = dbo.BigVariantFromVariant(@testInput) 153 | SELECT @testVar.AsVariant 154 | -- returns 1.79E+308 155 | ``` 156 | 157 | --- 158 | #### Method UserDefinedFunctions.BigVariantFromDateTime2(System.Nullable{System.DateTime}) 159 | 160 | Take the given DATETIME2 object and convert it into a BigVariant. 161 | 162 | |Name | Description | 163 | |-----|------| 164 | |value: |a DATETIME2 to wrap in a BigVariant| 165 | **Returns**: A BigVariant containing the given DATETIME2 166 | 167 | --- 168 | #### Method UserDefinedFunctions.BigVariantFromString(System.Data.SqlTypes.SqlString) 169 | 170 | Take the given NVARCHAR(MAX) or TEXT or NTEXT object and convert it into a BigVariant. 171 | 172 | |Name | Description | 173 | |-----|------| 174 | |value: |an NVARCHAR(MAX) or TEXT or NTEXT to wrap in a BigVariant| 175 | **Returns**: A BigVariant containing the given NVARCHAR(MAX) or TEXT or NTEXT 176 | 177 | ##### Example: 178 | 179 | ###### SQL code 180 | 181 | ``` 182 | DECLARE @testString NVARCHAR(MAX) 183 | DECLARE @testVar BigVariant 184 | SET @testString = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus.' + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) 185 | + 'Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum. Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc, quis gravida magna mi a libero. Fusce vulputate eleifend sapien. Vestibulum purus quam, scelerisque ut, mollis sed, nonummy id, metus. Nullam accumsan lorem in dui. Cras ultricies mi eu turpis hendrerit fringilla. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; In ac dui quis mi consectetuer lacinia. Nam pretium turpis et arcu. Duis arcu tortor, suscipit eget, imperdiet nec, imperdiet iaculis, ipsum.' + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) 186 | + 'Sed aliquam ultrices mauris. Integer ante arcu, accumsan a, consectetuer eget, posuere ut, mauris. Praesent adipiscing. Phasellus ullamcorper ipsum rutrum nunc. Nunc nonummy metus. Vestibulum volutpat pretium libero. Cras id dui. Aenean ut eros et nisl sagittis vestibulum. Nullam nulla eros, ultricies sit amet, nonummy id, imperdiet feugiat, pede. Sed lectus. Donec mollis hendrerit risus. Phasellus nec sem in justo pellentesque facilisis. Etiam imperdiet imperdiet orci. Nunc nec neque. Phasellus leo dolor, tempus non, auctor et, hendrerit quis, nisi. Curabitur ligula sapien, tincidunt non, euismod vitae, posuere imperdiet, leo. Maecenas malesuada. Praesent congue erat at massa. Sed cursus turpis vitae tortor. Donec posuere vulputate arcu. Phasellus accumsan cursus velit.' + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) 187 | SET @testVar = dbo.BigVariantFromString(@testString) 188 | ``` 189 | 190 | --- 191 | #### Method UserDefinedFunctions.BigVariantFromBinary(System.Data.SqlTypes.SqlBinary) 192 | 193 | Take the given VARBINARY(MAX) or IMAGE or other binary object and convert it into a BigVariant. 194 | 195 | |Name | Description | 196 | |-----|------| 197 | |value: |an VARBINARY(MAX) or IMAGE or other binary to wrap in a BigVariant| 198 | **Returns**: A BigVariant containing the given VARBINARY(MAX) or IMAGE or other binary 199 | 200 | --- 201 | 202 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.Test/UnexpectedElement.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Text.RegularExpressions; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | 6 | namespace PxtlCa.XmlCommentMarkDownGenerator.Test 7 | { 8 | [TestClass] 9 | public class UnexpectedElement 10 | { 11 | [TestMethod] 12 | [ExpectedException(typeof(System.Xml.XmlException))] 13 | public void TestUnexpectedElementError() 14 | { 15 | var inputResourceName = "PxtlCa.XmlCommentMarkDownGenerator.Test.UnexpectedElement_input.xml"; 16 | var testInput = Util.Helper.FetchResourceAsString(inputResourceName); 17 | 18 | //exception thrown below 19 | var testOutput = testInput.ToMarkDown(); 20 | } 21 | 22 | [TestMethod] 23 | public void TestUnexpectedElementWarning() 24 | { 25 | var inputResourceName = "PxtlCa.XmlCommentMarkDownGenerator.Test.UnexpectedElement_input.xml"; 26 | Regex normalizeSpace = new Regex(@"\s+", RegexOptions.Compiled); 27 | var testInput = Util.Helper.FetchResourceAsString(inputResourceName); 28 | var warningLogger = new Util.TestWarningLogger(); 29 | var context = new ConversionContext 30 | { 31 | UnexpectedTagAction = UnexpectedTagActionEnum.Warn, 32 | WarningLogger = warningLogger 33 | }; 34 | 35 | //exception thrown below 36 | var testOutput = normalizeSpace.Replace(testInput.ToMarkDown(context), " "); 37 | Assert.IsTrue(warningLogger.WarningList.Any(w => w.Contains("Unknown element type"))); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.Test/UnexpectedElement_input.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | PxtlCa.TestAssembly 5 | 6 | 7 | 8 | 9 | The TestType type. 10 | 11 | this should cause an error 12 | 13 | 14 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.Test/Util/Helper.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Reflection; 3 | 4 | namespace PxtlCa.XmlCommentMarkDownGenerator.Test.Util 5 | { 6 | public static class Helper 7 | { 8 | public static string FetchResourceAsString(string resourceName) 9 | { 10 | var assembly = Assembly.GetExecutingAssembly(); 11 | using (Stream stream = assembly.GetManifestResourceStream(resourceName)) 12 | using (StreamReader reader = new StreamReader(stream)) 13 | { 14 | return reader.ReadToEnd(); 15 | } 16 | } 17 | 18 | public static string GetRegressionTestXml() 19 | { 20 | var inputResourceName = "PxtlCa.XmlCommentMarkDownGenerator.Test.RegressionBigVariant_input.xml"; 21 | return FetchResourceAsString(inputResourceName); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.Test/Util/TestWarningLogger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PxtlCa.XmlCommentMarkDownGenerator.Test.Util 8 | { 9 | public class TestWarningLogger : IWarningLogger 10 | { 11 | public List WarningList { get; private set; } = new List(); 12 | public void LogWarning(string warning) 13 | { 14 | WarningList.Add(warning); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | PxtlCa.XmlCommentMarkDownGenerator 5 | 0.3.0.0 6 | PxtlCa.XmlCommentMarkDownGenerator 7 | Martin Zarate 8 | https://opensource.org/licenses/MIT 9 | https://github.com/Pxtl/XmlCommentMarkDownGenerator 10 | false 11 | Convert Visual Studio generated XML Comment XML files into Github-flavoured MarkDown. 12 | Guide available at https://github.com/Pxtl/XmlCommentMarkDownGenerator/blob/master/README.md 13 | 2016 Martin Zarate 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 18 | 19 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator/ConversionContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PxtlCa.XmlCommentMarkDownGenerator 8 | { 9 | /// 10 | /// Helper internal class for the Node conversion 11 | /// 12 | public class ConversionContext 13 | { 14 | /// 15 | /// Warning log writer. Throws exceptions if null. 16 | /// 17 | public IWarningLogger WarningLogger { get; set; } 18 | public string AssemblyName { get; set; } 19 | public ConversionContext MutateAssemblyName(string assemblyName) 20 | { 21 | AssemblyName = assemblyName; 22 | return this; 23 | } 24 | public UnexpectedTagActionEnum UnexpectedTagAction { get; set; } = UnexpectedTagActionEnum.Error; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator/IWarningLogger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace PxtlCa.XmlCommentMarkDownGenerator 9 | { 10 | public interface IWarningLogger 11 | { 12 | void LogWarning(string warning); 13 | } 14 | 15 | public class TextWriterWarningLogger : IWarningLogger 16 | { 17 | private TextWriter _textWriter; 18 | public TextWriterWarningLogger(TextWriter textWriter) 19 | { 20 | _textWriter = textWriter; 21 | } 22 | public void LogWarning(string warning) 23 | { 24 | _textWriter.WriteLine("WARN: " + warning); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator/Options.cs: -------------------------------------------------------------------------------- 1 | using CommandLine; 2 | using CommandLine.Text; 3 | 4 | namespace PxtlCa.XmlCommentMarkDownGenerator 5 | { 6 | public class Options 7 | { 8 | [Option('i', "inputfile", HelpText = "Input xml file to read.")] 9 | public string InputFile { get; set; } 10 | 11 | [Option("cin", HelpText = "Read input from console instead of file.")] 12 | public bool ConsoleIn { get; set; } 13 | 14 | [Option('o', "outputfile", HelpText = "Output md file to write.")] 15 | public string OutputFile { get; set; } 16 | 17 | [Option("cout", HelpText = "Write output to console instead of file.")] 18 | public bool ConsoleOut { get; set; } 19 | 20 | [Option('u', "unexpected", HelpText = "Handled unexpected tags as " + nameof(UnexpectedTagActionEnum.Accept) + ", " + nameof(UnexpectedTagActionEnum.Warn) + ", or " + nameof(UnexpectedTagActionEnum.Error) + ".")] 21 | public UnexpectedTagActionEnum UnexpectedTagAction { get; set; } 22 | 23 | //[Option('v', null, HelpText = "Print details during execution.")] 24 | //public bool Verbose { get; set; } 25 | 26 | [HelpOption] 27 | public string GetUsage() 28 | { 29 | return HelpText.AutoBuild(this, (HelpText current) => HelpText.DefaultParsingErrorsHandler(this, current)); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Xml.Linq; 4 | using CommandLine; 5 | 6 | namespace PxtlCa.XmlCommentMarkDownGenerator 7 | { 8 | class Program 9 | { 10 | static void Main(string[] args) 11 | { 12 | var options = new Options(); 13 | if (Parser.Default.ParseArguments(args, options)) 14 | { 15 | if (!options.ConsoleIn && options.InputFile == null 16 | || !options.ConsoleOut && options.OutputFile == null) 17 | { 18 | Console.WriteLine(options.GetUsage()); 19 | return; 20 | } 21 | // consume Options instance properties 22 | var inReader = options.ConsoleIn 23 | ? Console.In 24 | : new StreamReader(options.InputFile); 25 | using (var outWriter = options.ConsoleIn 26 | ? Console.Out 27 | : new StreamWriter(options.OutputFile) 28 | ) 29 | { 30 | var xml = inReader.ReadToEnd(); 31 | var doc = XDocument.Parse(xml); 32 | var context = new ConversionContext() { UnexpectedTagAction = options.UnexpectedTagAction, WarningLogger = new TextWriterWarningLogger(Console.Error) }; 33 | var md = doc.Root.ToMarkDown(context); 34 | outWriter.Write(md); 35 | outWriter.Close(); 36 | } 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using CommandLine; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("PxtlCa.XmlCommentMarkDownGenerator")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("PxtlCa.XmlCommentMarkDownGenerator")] 14 | [assembly: AssemblyCopyright("Copyright © 2016")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | [assembly: AssemblyUsage( 18 | "Usage: PxtlCa.XmlCommentMarkDownGenerator -i InputFileName.xml -o OutputFileName.md")] 19 | 20 | [assembly: AssemblyLicense( 21 | "This is free software. You may redistribute copies of it under the terms of", 22 | "the MIT License .")] 23 | 24 | // Setting ComVisible to false makes the types in this assembly not visible 25 | // to COM components. If you need to access a type in this assembly from 26 | // COM, set the ComVisible attribute to true on that type. 27 | [assembly: ComVisible(false)] 28 | 29 | // The following GUID is for the ID of the typelib if this project is exposed to COM 30 | [assembly: Guid("1375dc94-03f8-496c-981c-d5d6e1b0fd26")] 31 | 32 | // Version information for an assembly consists of the following four values: 33 | // 34 | // Major Version 35 | // Minor Version 36 | // Build Number 37 | // Revision 38 | // 39 | // You can specify all the values or you can default the Build and Revision Numbers 40 | // by using the '*' as shown below: 41 | // [assembly: AssemblyVersion("1.0.*")] 42 | [assembly: AssemblyVersion("0.3.*")] 43 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator/PxtlCa.XmlCommentMarkDownGenerator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {1375DC94-03F8-496C-981C-D5D6E1B0FD26} 8 | Exe 9 | Properties 10 | PxtlCa.XmlCommentMarkDownGenerator 11 | PxtlCa.XmlCommentMarkDownGenerator 12 | v4.5.2 13 | 512 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | ..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll 38 | True 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 71 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator/TagRenderers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Xml.Linq; 4 | 5 | namespace PxtlCa.XmlCommentMarkDownGenerator 6 | { 7 | public class TagRenderer 8 | { 9 | public TagRenderer(string formatString, Func> valueExtractor) 10 | { 11 | FormatString = formatString; 12 | ValueExtractor = valueExtractor; 13 | } 14 | 15 | public string FormatString { get; } = ""; 16 | 17 | public Func< 18 | XElement, //xml Element to extract from 19 | ConversionContext, //context 20 | IEnumerable //resultant list of values that will get used with formatString 21 | > ValueExtractor; 22 | 23 | public static Dictionary Dict { get; } = new Dictionary() 24 | { 25 | ["doc"] = new TagRenderer( 26 | "# {0} #\n\n{1}\n\n", 27 | (x, context) => new[]{ 28 | x.Element("assembly").Element("name").Value, 29 | x.Element("members").Elements("member").ToMarkDown(context.MutateAssemblyName(x.Element("assembly").Element("name").Value)) 30 | } 31 | ), 32 | ["type"] = new TagRenderer( 33 | "## {0}\n\n{1}\n\n---\n", 34 | (x, context) => XmlToMarkdown.ExtractNameAndBodyFromMember(x, context) 35 | ), 36 | ["field"] = new TagRenderer( 37 | "#### {0}\n\n{1}\n\n---\n", 38 | (x, context) => XmlToMarkdown.ExtractNameAndBodyFromMember(x, context) 39 | ), 40 | ["property"] = new TagRenderer( 41 | "#### {0}\n\n{1}\n\n---\n", 42 | (x, context) => XmlToMarkdown.ExtractNameAndBodyFromMember(x, context) 43 | ), 44 | ["method"] = new TagRenderer( 45 | "#### {0}\n\n{1}\n\n---\n", 46 | (x, context) => XmlToMarkdown.ExtractNameAndBodyFromMember(x, context) 47 | ), 48 | ["event"] = new TagRenderer( 49 | "#### {0}\n\n{1}\n\n---\n", 50 | (x, context) => XmlToMarkdown.ExtractNameAndBodyFromMember(x, context) 51 | ), 52 | ["summary"] = new TagRenderer( 53 | "{0}\n\n", 54 | (x, context) => new[] { x.Nodes().ToMarkDown(context) } 55 | ), 56 | ["value"] = new TagRenderer( 57 | "**Value**: {0}\n\n", 58 | (x, context) => new[] { x.Nodes().ToMarkDown(context) } 59 | ), 60 | ["remarks"] = new TagRenderer( 61 | "\n\n>{0}\n\n", 62 | (x, context) => new[] { x.Nodes().ToMarkDown(context) } 63 | ), 64 | ["example"] = new TagRenderer( 65 | "##### Example: {0}\n\n", 66 | (x, context) => new[] { x.Nodes().ToMarkDown(context) } 67 | ), 68 | ["para"] = new TagRenderer( 69 | "{0}\n\n", 70 | (x, context) => new[] { x.Nodes().ToMarkDown(context) } 71 | ), 72 | ["code"] = new TagRenderer( 73 | "\n\n###### {0} code\n\n```\n{1}\n```\n\n", 74 | (x, context) => new[] { x.Attribute("lang")?.Value ?? "", x.Value.ToCodeBlock() } 75 | ), 76 | ["seePage"] = new TagRenderer( 77 | "[[{1}|{0}]]", 78 | (x, context) => XmlToMarkdown.ExtractNameAndBody("cref", x, context) 79 | ), 80 | ["seeAnchor"] = new TagRenderer( 81 | "[{1}]({0})]", 82 | (x, context) => { var xx = XmlToMarkdown.ExtractNameAndBody("cref", x, context); xx[0] = xx[0].ToLower(); return xx; } 83 | ), 84 | ["firstparam"] = new TagRenderer( 85 | "|Name | Description |\n|-----|------|\n|{0}: |{1}|\n", 86 | (x, context) => XmlToMarkdown.ExtractNameAndBody("name", x, context) 87 | ), 88 | ["typeparam"] = new TagRenderer( 89 | "|{0}: |{1}|\n", 90 | (x, context) => XmlToMarkdown.ExtractNameAndBody("name", x, context) 91 | ), 92 | ["param"] = new TagRenderer( 93 | "|{0}: |{1}|\n", 94 | (x, context) => XmlToMarkdown.ExtractNameAndBody("name", x, context) 95 | ), 96 | ["paramref"] = new TagRenderer( 97 | "`{0}`", 98 | (x, context) => XmlToMarkdown.ExtractNameAndBody("name", x, context) 99 | ), 100 | ["exception"] = new TagRenderer( 101 | "[[{0}|{0}]]: {1}\n\n", 102 | (x, context) => XmlToMarkdown.ExtractNameAndBody("cref", x, context) 103 | ), 104 | ["returns"] = new TagRenderer( 105 | "**Returns**: {0}\n\n", 106 | (x, context) => new[] { x.Nodes().ToMarkDown(context) } 107 | ), 108 | ["c"] = new TagRenderer( 109 | " `{0}` ", 110 | (x, context) => new[] { x.Nodes().ToMarkDown(context) } 111 | ), 112 | ["none"] = new TagRenderer( 113 | "", 114 | (x, context) => new string[0] 115 | ), 116 | }; 117 | } 118 | 119 | 120 | } 121 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator/UnexpectedTagActionEnum.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PxtlCa.XmlCommentMarkDownGenerator 8 | { 9 | /// 10 | /// Specifies the manner in which unexpected tags will be handled 11 | /// 12 | public enum UnexpectedTagActionEnum 13 | { 14 | /// 15 | /// No unexpected tags are allowed 16 | /// 17 | Error, 18 | /// 19 | /// Warn on unexpected tags 20 | /// 21 | Warn, 22 | /// 23 | /// All unexpected tags are allowed 24 | /// 25 | Accept 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator/XmlToMarkDown.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text.RegularExpressions; 6 | using System.Xml; 7 | using System.Xml.Linq; 8 | 9 | namespace PxtlCa.XmlCommentMarkDownGenerator 10 | { 11 | public static class XmlToMarkdown 12 | { 13 | public static string ToMarkDown(this string s) 14 | { 15 | return s.ToMarkDown(new ConversionContext { 16 | UnexpectedTagAction = UnexpectedTagActionEnum.Error 17 | , WarningLogger = new TextWriterWarningLogger(Console.Error) 18 | }); 19 | } 20 | 21 | public static string ToMarkDown(this string s, ConversionContext context) 22 | { 23 | var xdoc = XDocument.Parse(s); 24 | return xdoc 25 | .ToMarkDown(context) 26 | .RemoveRedundantLineBreaks(); 27 | } 28 | 29 | public static string ToMarkDown(this Stream s) 30 | { 31 | var xdoc = XDocument.Load(s); 32 | return xdoc 33 | .ToMarkDown(new ConversionContext { UnexpectedTagAction = UnexpectedTagActionEnum.Error, WarningLogger = new TextWriterWarningLogger(Console.Error) }) 34 | .RemoveRedundantLineBreaks(); 35 | } 36 | 37 | private static Dictionary _MemberNamePrefixDict = new Dictionary(StringComparer.OrdinalIgnoreCase) { 38 | ["F:"] = "Field", 39 | ["P:"] = "Property", 40 | ["T:"] = "Type", 41 | ["E:"] = "Event", 42 | ["M:"] = "Method", 43 | }; 44 | 45 | /// 46 | /// Write out the given XML Node as Markdown. Recursive function used internally. 47 | /// 48 | /// The xml node to write out. 49 | /// The Conversion Context that will be passed around and manipulated over the course of the translation. 50 | /// The converted markdown text. 51 | public static string ToMarkDown(this XNode node, ConversionContext context) 52 | { 53 | if(node is XDocument) 54 | { 55 | node = ((XDocument)node).Root; 56 | } 57 | 58 | string name; 59 | if (node.NodeType == XmlNodeType.Element) 60 | { 61 | var el = (XElement)node; 62 | name = el.Name.LocalName; 63 | if (name == "member") 64 | { 65 | string expandedName = null; 66 | if(!_MemberNamePrefixDict.TryGetValue(el.Attribute("name").Value.Substring(0,2), out expandedName)) 67 | { 68 | expandedName = "none"; 69 | } 70 | name = expandedName.ToLowerInvariant(); 71 | } 72 | if (name == "see") 73 | { 74 | var anchor = el.Attribute("cref") != null && el.Attribute("cref").Value.StartsWith("!:#"); 75 | name = anchor ? "seeAnchor" : "seePage"; 76 | } 77 | //treat first Param element separately to add table headers. 78 | if (name.EndsWith("param") 79 | && node 80 | .ElementsBeforeSelf() 81 | .LastOrDefault() 82 | ?.Name 83 | ?.LocalName != "param") 84 | { 85 | name = "firstparam"; 86 | } 87 | 88 | try { 89 | var vals = TagRenderer.Dict[name].ValueExtractor(el, context).ToArray(); 90 | return string.Format(TagRenderer.Dict[name].FormatString, args: vals); 91 | } 92 | catch(KeyNotFoundException ex) 93 | { 94 | var lineInfo = (IXmlLineInfo)node; 95 | switch(context.UnexpectedTagAction) 96 | { 97 | case UnexpectedTagActionEnum.Error: 98 | throw new XmlException($@"Unknown element type ""{ name }""", ex, lineInfo.LineNumber, lineInfo.LinePosition); 99 | case UnexpectedTagActionEnum.Warn: 100 | context.WarningLogger.LogWarning($@"Unknown element type ""{ name }"" on line {lineInfo.LineNumber}, pos {lineInfo.LinePosition}"); 101 | break; 102 | case UnexpectedTagActionEnum.Accept: 103 | //do nothing; 104 | break; 105 | default: 106 | throw new InvalidOperationException($"Unexpected {nameof(UnexpectedTagActionEnum)}"); 107 | } 108 | } 109 | } 110 | 111 | 112 | if (node.NodeType == XmlNodeType.Text) 113 | return Regex.Replace(((XText)node).Value.Replace('\n', ' '), @"\s+", " "); 114 | 115 | return ""; 116 | } 117 | 118 | private static readonly Regex _PrefixReplacerRegex = new Regex(@"(^[A-Z]\:)"); 119 | 120 | internal static string[] ExtractNameAndBodyFromMember(XElement node, ConversionContext context) 121 | { 122 | var newName = Regex.Replace(node.Attribute("name").Value, $@":{Regex.Escape(context.AssemblyName)}\.", ":"); //remove leading namespace if it matches the assembly name 123 | //TODO: do same for function parameters 124 | newName = _PrefixReplacerRegex.Replace(newName, match => _MemberNamePrefixDict[match.Value] + " "); //expand prefixes into more verbose words for member. 125 | return new[] 126 | { 127 | newName, 128 | node.Nodes().ToMarkDown(context) 129 | }; 130 | } 131 | 132 | internal static string[] ExtractNameAndBody(string att, XElement node, ConversionContext context) 133 | { 134 | return new[] 135 | { 136 | node.Attribute(att)?.Value, 137 | node.Nodes().ToMarkDown(context) 138 | }; 139 | } 140 | 141 | internal static string ToMarkDown(this IEnumerable es, ConversionContext context) 142 | { 143 | return es.Aggregate("", (current, x) => current + x.ToMarkDown(context)); 144 | } 145 | 146 | internal static string ToCodeBlock(this string s) 147 | { 148 | var lines = s.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); 149 | var blank = lines[0].TakeWhile(x => x == ' ').Count() - 4; 150 | return string.Join("\n", lines.Select(x => new string(x.SkipWhile((y, i) => i < blank).ToArray()))).TrimEnd(); 151 | } 152 | 153 | static string RemoveRedundantLineBreaks(this string s) 154 | { 155 | return Regex.Replace(s, @"\n\n\n+", "\n\n"); 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkDownGenerator/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkdownGenerator.MSBuild.Test/BuildEngine.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using Microsoft.Build.Framework; 4 | using Microsoft.Build.Tasks; 5 | using Microsoft.Build.Utilities; 6 | using PxtlCa.XmlCommentMarkDownGenerator; 7 | using PxtlCa.XmlCommentMarkDownGenerator.MSBuild; 8 | using Rhino.Mocks; 9 | using System.IO; 10 | using System.Xml.Linq; 11 | using System.Xml.XPath; 12 | using System.Xml; 13 | using System.Linq; 14 | 15 | namespace PxtlCa.XmlCommentMarkDownGenerator.MSBuild.Test 16 | { 17 | [TestClass] 18 | public class TestMerges 19 | { 20 | [TestMethod] 21 | public void ExecuteDefaultMerge() 22 | { 23 | var defaultMergeSearchText = "DefaultMergeSearchHeaderText"; 24 | PrepareInputDocsDirectory("Notes", $@" 25 | --- 26 | --- 27 | ## {defaultMergeSearchText} 28 | ".Trim()); 29 | PrepareStandardOutputDocsDirectory(); 30 | var mockRepo = new MockRepository(); 31 | var buildEngine = mockRepo.Stub(); 32 | 33 | var xmlFileName = "DefaultMerge.xml"; 34 | File.WriteAllText(xmlFileName, PxtlCa.XmlCommentMarkDownGenerator.Test.Util.Helper.GetRegressionTestXml()); 35 | 36 | var task = new GenerateMarkdown 37 | { 38 | BuildEngine = buildEngine, 39 | SourceDocumentDirPath = new TaskItem(InputDocsDirectory), 40 | TargetDocumentDirPath = new TaskItem(OutputDocsDirectory), 41 | InputXml = new ITaskItem[] { new TaskItem(xmlFileName) } 42 | }; 43 | 44 | task.Execute(); 45 | 46 | var fileActuallyExists = Directory.EnumerateFiles(OutputDocsDirectory) 47 | .Any(f => File.ReadAllText(f).Contains(defaultMergeSearchText)); 48 | 49 | Assert.IsTrue(fileActuallyExists); 50 | } 51 | 52 | [TestMethod] 53 | public void HandleUnexpectedTag() 54 | { 55 | PrepareStandardInputDocsDirectory(); 56 | PrepareStandardOutputDocsDirectory(); 57 | var mockRepo = new MockRepository(); 58 | var buildEngine = mockRepo.Stub(); 59 | 60 | var toAlter = PxtlCa.XmlCommentMarkDownGenerator.Test.Util.Helper.GetRegressionTestXml(); 61 | toAlter = toAlter.Replace(@"", @"X"); 62 | 63 | var alteredPath = @"MSBuild_alteredWarning.xml"; 64 | File.WriteAllText(alteredPath, toAlter); 65 | 66 | var task = new GenerateMarkdown 67 | { 68 | BuildEngine = buildEngine, 69 | SourceDocumentDirPath = new TaskItem(InputDocsDirectory), 70 | TargetDocumentDirPath = new TaskItem(OutputDocsDirectory), 71 | InputXml = new ITaskItem[] { new TaskItem(alteredPath) }, 72 | UnexpectedTagAction = UnexpectedTagActionEnum.Accept 73 | }; 74 | 75 | task.Execute(); 76 | if (null != task.LoggedException) 77 | { 78 | throw task.LoggedException; 79 | } 80 | } 81 | 82 | 83 | [TestMethod] 84 | [ExpectedException(typeof(XmlException))] 85 | public void ExpectedErrorUnexpectedTag() 86 | { 87 | PrepareStandardInputDocsDirectory(); 88 | PrepareStandardOutputDocsDirectory(); 89 | var mockRepo = new MockRepository(); 90 | var buildEngine = mockRepo.Stub(); 91 | 92 | var toAlter = PxtlCa.XmlCommentMarkDownGenerator.Test.Util.Helper.GetRegressionTestXml(); 93 | toAlter = toAlter.Replace(@"", @"X"); 94 | 95 | var alteredPath = @"MSBuild_alteredError.xml"; 96 | File.WriteAllText(alteredPath, toAlter); 97 | 98 | var task = new GenerateMarkdown 99 | { 100 | BuildEngine = buildEngine, 101 | SourceDocumentDirPath = new TaskItem(InputDocsDirectory), 102 | TargetDocumentDirPath = new TaskItem(OutputDocsDirectory), 103 | InputXml = new ITaskItem[] { new TaskItem(alteredPath) }, 104 | UnexpectedTagAction = XmlCommentMarkDownGenerator.UnexpectedTagActionEnum.Error 105 | }; 106 | 107 | task.Execute(); 108 | 109 | if (null != task.LoggedException) 110 | { 111 | throw task.LoggedException; 112 | } 113 | } 114 | 115 | public static void PrepareStandardOutputDocsDirectory() 116 | { 117 | PrepareDirectory(OutputDocsDirectory); 118 | } 119 | public static void PrepareStandardInputDocsDirectory() 120 | { 121 | PrepareInputDocsDirectory("Notes", @" 122 | --- 123 | --- 124 | ## No Documentation Yet Authored 125 | "); 126 | } 127 | 128 | public static readonly string OutputDocsDirectory = "OutputDocs"; 129 | public static readonly string InputDocsDirectory = "InputDocs"; 130 | 131 | public static void PrepareInputDocsDirectory(string mdDocFileNameSansExtension, string mdDocFileBody) 132 | { 133 | PrepareDirectory(InputDocsDirectory); 134 | File.WriteAllText($@"{InputDocsDirectory}\{mdDocFileNameSansExtension}.md", mdDocFileBody.Trim()); 135 | } 136 | 137 | private static void PrepareDirectory(string directoryName) 138 | { 139 | if (Directory.Exists(directoryName)) 140 | { 141 | Directory.Delete(directoryName, true); 142 | } 143 | Directory.CreateDirectory(directoryName); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkdownGenerator.MSBuild.Test/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | [assembly: AssemblyTitle("PxtlCa.XmlCommentMarkDownGenerator.MSBuild.Test")] 6 | [assembly: AssemblyDescription("")] 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("PxtlCa.XmlCommentMarkDownGenerator.MSBuild.Test")] 10 | [assembly: AssemblyCopyright("Copyright © 2017")] 11 | [assembly: AssemblyTrademark("")] 12 | [assembly: AssemblyCulture("")] 13 | 14 | [assembly: ComVisible(false)] 15 | 16 | [assembly: Guid("2358183d-b57c-467d-b89c-16c6be040753")] 17 | 18 | // [assembly: AssemblyVersion("1.0.*")] 19 | [assembly: AssemblyVersion("1.0.0.0")] 20 | [assembly: AssemblyFileVersion("1.0.0.0")] 21 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkdownGenerator.MSBuild.Test/PxtlCa.XmlCommentMarkdownGenerator.MSBuild.Test.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {2358183D-B57C-467D-B89C-16C6BE040753} 8 | Library 9 | Properties 10 | PxtlCa.XmlCommentMarkdownGenerator.MSBuild.Test 11 | PxtlCa.XmlCommentMarkdownGenerator.MSBuild.Test 12 | v4.5.2 13 | 512 14 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 15.0 16 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 17 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 18 | False 19 | UnitTest 20 | 21 | 22 | 23 | 24 | true 25 | full 26 | false 27 | bin\Debug\ 28 | DEBUG;TRACE 29 | prompt 30 | 4 31 | 32 | 33 | pdbonly 34 | true 35 | bin\Release\ 36 | TRACE 37 | prompt 38 | 4 39 | 40 | 41 | 42 | 43 | 44 | 45 | ..\packages\RhinoMocks.3.6.1\lib\net\Rhino.Mocks.dll 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | False 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | {9fcee209-508f-474e-80c2-d0966e4aa126} 76 | PxtlCa.XmlCommentMarkDownGenerator.MSBuild 77 | 78 | 79 | {7993d07f-7f81-477e-aba1-e3e6dc5cab6a} 80 | PxtlCa.XmlCommentMarkDownGenerator.Test 81 | 82 | 83 | {1375dc94-03f8-496c-981c-d5d6e1b0fd26} 84 | PxtlCa.XmlCommentMarkDownGenerator 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /PxtlCa.XmlCommentMarkdownGenerator.MSBuild.Test/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XmlCommentMarkDownGenerator 2 | 3 | Generates Markdown from VS XML documentation file. Forked from https://gist.github.com/lontivero/593fc51f1208555112e0 4 | 5 | XmlCommentMarkDownGenerator is available as both a command-line tool and as an MSBuild target. 6 | There is not currently feature-parity between these two modes. 7 | Features involving merging a MarkDown document into the generated file are currently target-only. 8 | 9 | ## Command Line Tool 10 | 11 | Usage: PxtlCa.XmlCommentMarkDownGenerator -i InputFileName.xml -o OutputFileName.md 12 | 13 | -i, --inputfile Input xml file to read. 14 | 15 | --cin Read input from console instead of file. 16 | 17 | -o, --outputfile Output md file to write. 18 | 19 | --cout Write output to console instead of file. 20 | 21 | --help Display this help screen. 22 | 23 | Execute PxtlCa.XmlCommentMarkDownGenerator.exe --help for usage if the above is out-of-date. 24 | 25 | ## Nuget Package/MsBuild Target 26 | 27 | https://www.nuget.org/packages/PxtlCa.XmlCommentMarkDownGenerator 28 | 29 | When used as a nuget package, it will add an MSBuild task to your project to automatically convert generated xml into markdown file stored in Docs at the project level. It will also merge any existing markdown files in Docs with the converted markdown. Takes multiple input xml files. 30 | 31 | (note: the above nuget target was broken after 0.1.5977.1837 because I forgot to commit the nuspec line that does it. Oops. Fixed in 0.2.6130.564) 32 | 33 | You must have XML documentation output enabled for your project in both debug and release configurations or it will warn that it can't find the file. 34 | 35 | In the basic case, this is all you need. However, if you need to merge with other markdown documents, XmlCommentMarkDownGenerator has additional features. 36 | 37 | ### Working Files and Directories 38 | 39 | Assuming your project follows this layout 40 | 41 | - root 42 | - docs 43 | - myApplication 44 | - program.cs 45 | - readme.md 46 | - myApplication.Lib 47 | - class1.cs 48 | - class2.cs 49 | - readme.md 50 | - myApplication.Tests 51 | - test1.cs 52 | - test2.cs 53 | - readme.md 54 | - myApplication.sln 55 | - readme.md 56 | 57 | Given this typical layout, if we apply XmlCommentMarkDownGenerator to myApplication.Lib, 58 | the program will search for .md files in myApplication.Lib's folder. 59 | 60 | The .md file will be considered an eligible markdown header if it matches one of the following criteria: 61 | 62 | 1) The file contains a YAML header block (more on this later) 63 | 2) The file is named "readme.md" (case-insensitive) 64 | 3) The file is named to match the assembly (in the case of this example, "myApplication.Lib.md") 65 | 66 | In that order. If the generator finds files with YAML header blocks in the project folder, 67 | it will not search by filename. 68 | 69 | When it finds the file, it will generate the MD from the generated XML, 70 | append it to the end of the text in the found header file, and write out the result 71 | at /docs/"assemblyName".md. So in our example case, it would be /docs/myApplication.lib.md. 72 | 73 | ### YAML Header Blocks 74 | 75 | For more precise control, you can modify your header file with a YAML header block. Example below: 76 | 77 | ```yaml 78 | --- 79 | UnexpectedTagAction: Error 80 | OutputFile: myApplicationNameChanged.lib.md 81 | MergeSequence: 1 82 | --- 83 | ``` 84 | 85 | This would be followed by normal MarkDown text. 86 | Note that the YAML parser requires the three dashes to be the very first line in the file. 87 | 88 | - **UnexpectedTagAction**: can be one of Error, Warn, or None. Determines how the generator should respond to an unexpected XML tag. 89 | - **OutputFile**: path including filename of the output file. Relative to the ../Docs folder. 90 | - **MergeSequence**: If merging multiple files into the same output file, this entry will be used to order them using a crude natural sort. 91 | 92 | Note that the merge sequence is meaningless in typical workflow - each project generates one XML files, 93 | and each executes the markdown generator separately. 94 | 95 | ### MSBuild Options and Merging Multiple Files 96 | 97 | If you wish to manually customize your proj files for msbuild, you can feed more complicated targets into the MSBuild processor. 98 | You can choose a better target to ../Docs, provide multiple XML files in a single execution (allowing your doc files to be concatenated together) 99 | and provide an alternate source documents folder. See GenerateMarkdown.cs for details. -------------------------------------------------------------------------------- /XmlCommentMarkDownGenerator.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26430.16 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9CB54D49-0D43-462C-B250-38BEB7F38312}" 7 | ProjectSection(SolutionItems) = preProject 8 | .gitattributes = .gitattributes 9 | .gitignore = .gitignore 10 | CONTRIB.txt = CONTRIB.txt 11 | LICENSE.txt = LICENSE.txt 12 | PxtlCa.XmlCommentMarkDownGenerator.nuspec = PxtlCa.XmlCommentMarkDownGenerator.nuspec 13 | PxtlCa.XmlCommentMarkDownGenerator.targets = PxtlCa.XmlCommentMarkDownGenerator.targets 14 | README.md = README.md 15 | EndProjectSection 16 | EndProject 17 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PxtlCa.XmlCommentMarkDownGenerator", "PxtlCa.XmlCommentMarkDownGenerator\PxtlCa.XmlCommentMarkDownGenerator.csproj", "{1375DC94-03F8-496C-981C-D5D6E1B0FD26}" 18 | EndProject 19 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PxtlCa.XmlCommentMarkDownGenerator.Test", "PxtlCa.XmlCommentMarkDownGenerator.Test\PxtlCa.XmlCommentMarkDownGenerator.Test.csproj", "{7993D07F-7F81-477E-ABA1-E3E6DC5CAB6A}" 20 | EndProject 21 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PxtlCa.XmlCommentMarkDownGenerator.MSBuild", "PxtlCa.XmlCommentMarkDownGenerator.MSBuild\PxtlCa.XmlCommentMarkDownGenerator.MSBuild.csproj", "{9FCEE209-508F-474E-80C2-D0966E4AA126}" 22 | EndProject 23 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PxtlCa.XmlCommentMarkDownGenerator.MSBuild.Test", "PxtlCa.XmlCommentMarkdownGenerator.MSBuild.Test\PxtlCa.XmlCommentMarkDownGenerator.MSBuild.Test.csproj", "{2358183D-B57C-467D-B89C-16C6BE040753}" 24 | EndProject 25 | Global 26 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 27 | Debug|Any CPU = Debug|Any CPU 28 | Release|Any CPU = Release|Any CPU 29 | EndGlobalSection 30 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 31 | {1375DC94-03F8-496C-981C-D5D6E1B0FD26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {1375DC94-03F8-496C-981C-D5D6E1B0FD26}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {1375DC94-03F8-496C-981C-D5D6E1B0FD26}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {1375DC94-03F8-496C-981C-D5D6E1B0FD26}.Release|Any CPU.Build.0 = Release|Any CPU 35 | {7993D07F-7F81-477E-ABA1-E3E6DC5CAB6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 36 | {7993D07F-7F81-477E-ABA1-E3E6DC5CAB6A}.Debug|Any CPU.Build.0 = Debug|Any CPU 37 | {7993D07F-7F81-477E-ABA1-E3E6DC5CAB6A}.Release|Any CPU.ActiveCfg = Release|Any CPU 38 | {7993D07F-7F81-477E-ABA1-E3E6DC5CAB6A}.Release|Any CPU.Build.0 = Release|Any CPU 39 | {9FCEE209-508F-474E-80C2-D0966E4AA126}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 40 | {9FCEE209-508F-474E-80C2-D0966E4AA126}.Debug|Any CPU.Build.0 = Debug|Any CPU 41 | {9FCEE209-508F-474E-80C2-D0966E4AA126}.Release|Any CPU.ActiveCfg = Release|Any CPU 42 | {9FCEE209-508F-474E-80C2-D0966E4AA126}.Release|Any CPU.Build.0 = Release|Any CPU 43 | {2358183D-B57C-467D-B89C-16C6BE040753}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 44 | {2358183D-B57C-467D-B89C-16C6BE040753}.Debug|Any CPU.Build.0 = Debug|Any CPU 45 | {2358183D-B57C-467D-B89C-16C6BE040753}.Release|Any CPU.ActiveCfg = Release|Any CPU 46 | {2358183D-B57C-467D-B89C-16C6BE040753}.Release|Any CPU.Build.0 = Release|Any CPU 47 | EndGlobalSection 48 | GlobalSection(SolutionProperties) = preSolution 49 | HideSolutionNode = FALSE 50 | EndGlobalSection 51 | GlobalSection(ExtensibilityGlobals) = postSolution 52 | SolutionGuid = {A014701D-154B-48B7-A856-5A277F53116D} 53 | EndGlobalSection 54 | EndGlobal 55 | --------------------------------------------------------------------------------