/// <summary> /// Generates Markdown from .NET XML documentation comments. /// </summary> /// <param name="inputPath">The input assembly.</param> /// <param name="outputPath">The output directory.</param> /// <param name="settings">The settings.</param> /// <returns>The names of files that were added, changed, or removed.</returns> public static XmlDocMarkdownResult Generate(string inputPath, string outputPath, XmlDocMarkdownSettings settings) { if (inputPath == null) { throw new ArgumentNullException(nameof(inputPath)); } if (outputPath == null) { throw new ArgumentNullException(nameof(outputPath)); } var result = new XmlDocMarkdownResult(); settings = settings ?? new XmlDocMarkdownSettings(); var generator = new MarkdownGenerator { SourceCodePath = settings.SourceCodePath, RootNamespace = settings.RootNamespace, IncludeObsolete = settings.IncludeObsolete, Visibility = settings.VisibilityLevel ?? XmlDocVisibilityLevel.Protected, ExternalDocs = settings.ExternalDocs, }; if (settings.NewLine != null) { generator.NewLine = settings.NewLine; } var assembly = Assembly.LoadFrom(inputPath); XmlDocAssembly xmlDocAssembly; var xmlDocPath = Path.ChangeExtension(inputPath, ".xml"); if (!File.Exists(xmlDocPath)) { xmlDocPath = Path.ChangeExtension(inputPath, ".XML"); } if (File.Exists(xmlDocPath)) { var xDocument = XDocument.Load(xmlDocPath); xmlDocAssembly = new XmlDocAssembly(xDocument); } else { xmlDocAssembly = new XmlDocAssembly(); } var namedTexts = generator.GenerateOutput(assembly, xmlDocAssembly); var namedTextsToWrite = new List <NamedText>(); foreach (var namedText in namedTexts) { string existingFilePath = Path.Combine(outputPath, namedText.Name); if (File.Exists(existingFilePath)) { // ignore CR when comparing files if (namedText.Text.Replace("\r", "") != File.ReadAllText(existingFilePath).Replace("\r", "")) { namedTextsToWrite.Add(namedText); result.Changed.Add(namedText.Name); if (!settings.IsQuiet) { result.Messages.Add("changed " + namedText.Name); } } } else { namedTextsToWrite.Add(namedText); result.Added.Add(namedText.Name); if (!settings.IsQuiet) { result.Messages.Add("added " + namedText.Name); } } } var namesToDelete = new List <string>(); if (settings.ShouldClean) { var directoryInfo = new DirectoryInfo(outputPath); if (directoryInfo.Exists) { string assemblyName = assembly.GetName().Name; string assemblyFilePath = assembly.Modules.FirstOrDefault()?.FullyQualifiedName; string assemblyFileName = assemblyFilePath != null?Path.GetFileName(assemblyFilePath) : assemblyName; string assemblyFolder = Path.GetFileNameWithoutExtension(assemblyFileName); var patterns = new[] { $"{assemblyFolder}/*.md", $"{assemblyFolder}/*/*.md" }; string codeGenComment = MarkdownGenerator.GetCodeGenComment(assemblyFileName); foreach (string nameMatchingPattern in FindNamesMatchingPatterns(directoryInfo, patterns, codeGenComment)) { if (namedTexts.All(x => x.Name != nameMatchingPattern)) { namesToDelete.Add(nameMatchingPattern); result.Removed.Add(nameMatchingPattern); if (!settings.IsQuiet) { result.Messages.Add("removed " + nameMatchingPattern); } } } } } if (!settings.IsDryRun) { if (!Directory.Exists(outputPath)) { Directory.CreateDirectory(outputPath); } foreach (var namedText in namedTextsToWrite) { string outputFilePath = Path.Combine(outputPath, namedText.Name); string outputFileDirectoryPath = Path.GetDirectoryName(outputFilePath); if (outputFileDirectoryPath != null && outputFileDirectoryPath != outputPath && !Directory.Exists(outputFileDirectoryPath)) { Directory.CreateDirectory(outputFileDirectoryPath); } File.WriteAllText(outputFilePath, namedText.Text); } foreach (string nameToDelete in namesToDelete) { File.Delete(Path.Combine(outputPath, nameToDelete)); } } return(result); }
/// <summary> /// Generates Markdown from .NET XML documentation comments. /// </summary> /// <param name="input">The input.</param> /// <param name="outputPath">The output directory.</param> /// <param name="settings">The settings.</param> /// <returns>The names of files that were added, changed, or removed.</returns> public static XmlDocMarkdownResult Generate(XmlDocInput input, string outputPath, XmlDocMarkdownSettings settings) { if (input == null) { throw new ArgumentNullException(nameof(input)); } if (outputPath == null) { throw new ArgumentNullException(nameof(outputPath)); } var result = new XmlDocMarkdownResult(); settings = settings ?? new XmlDocMarkdownSettings(); var generator = new MarkdownGenerator { SourceCodePath = settings.SourceCodePath, RootNamespace = settings.RootNamespace, IncludeObsolete = settings.IncludeObsolete, SkipUnbrowsable = settings.SkipUnbrowsable, Visibility = settings.VisibilityLevel ?? XmlDocVisibilityLevel.Protected, ExternalDocs = settings.ExternalDocs, NamespacePages = settings.NamespacePages, FrontMatter = settings.FrontMatter, }; if (settings.NewLine != null) { generator.NewLine = settings.NewLine; } if (string.Compare(settings.PermalinkStyle, "pretty", StringComparison.OrdinalIgnoreCase) == 0) { generator.PermalinkPretty = true; } XmlDocAssembly xmlDocAssembly; var assembly = input.Assembly; if (assembly == null) { assembly = Assembly.LoadFrom(input.AssemblyPath); } var xmlDocPath = input.XmlDocPath; if (xmlDocPath == null) { var assemblyPath = input.AssemblyPath ?? assembly.Location; xmlDocPath = Path.ChangeExtension(assemblyPath, ".xml"); if (!File.Exists(xmlDocPath)) { xmlDocPath = Path.ChangeExtension(assemblyPath, ".XML"); } } if (xmlDocPath != null && File.Exists(xmlDocPath)) { var xDocument = XDocument.Load(xmlDocPath); xmlDocAssembly = new XmlDocAssembly(xDocument); } else { xmlDocAssembly = new XmlDocAssembly(); } var namedTexts = generator.GenerateOutput(assembly, xmlDocAssembly); var namedTextsToWrite = new List <NamedText>(); foreach (var namedText in namedTexts) { string existingFilePath = Path.Combine(outputPath, namedText.Name); if (File.Exists(existingFilePath)) { // ignore CR when comparing files if (namedText.Text.Replace("\r", "") != File.ReadAllText(existingFilePath).Replace("\r", "")) { namedTextsToWrite.Add(namedText); result.Changed.Add(namedText.Name); if (!settings.IsQuiet) { result.Messages.Add("changed " + namedText.Name); } } } else { namedTextsToWrite.Add(namedText); result.Added.Add(namedText.Name); if (!settings.IsQuiet) { result.Messages.Add("added " + namedText.Name); } } } if (settings.GenerateToc) { string tocPath = Path.Combine(outputPath, "toc.yml"); NamedText root = namedTexts.FirstOrDefault(); if (root != null) { XmlDocToc toc = new XmlDocToc() { Path = root.Name, Title = root.Title, Prefix = settings.TocPrefix }; foreach (var namedText in namedTexts.Skip(1)) { toc.AddChild(namedText.Name, namedText.Parent, namedText.Title); } toc.Save(tocPath); } } var namesToDelete = new List <string>(); if (settings.ShouldClean) { var directoryInfo = new DirectoryInfo(outputPath); if (directoryInfo.Exists) { string assemblyName = assembly.GetName().Name; string assemblyFilePath = assembly.Modules.FirstOrDefault()?.FullyQualifiedName; string assemblyFileName = assemblyFilePath != null?Path.GetFileName(assemblyFilePath) : assemblyName; string assemblyFolder = Path.GetFileNameWithoutExtension(assemblyFileName); var patterns = new[] { $"{assemblyFolder}/*.md", $"{assemblyFolder}/*/*.md" }; string codeGenComment = MarkdownGenerator.GetCodeGenComment(assemblyFileName); foreach (string nameMatchingPattern in FindNamesMatchingPatterns(directoryInfo, patterns, codeGenComment)) { if (namedTexts.All(x => x.Name != nameMatchingPattern)) { namesToDelete.Add(nameMatchingPattern); result.Removed.Add(nameMatchingPattern); if (!settings.IsQuiet) { result.Messages.Add("removed " + nameMatchingPattern); } } } } } if (!settings.IsDryRun) { if (!Directory.Exists(outputPath)) { Directory.CreateDirectory(outputPath); } foreach (var namedText in namedTextsToWrite) { string outputFilePath = Path.Combine(outputPath, namedText.Name); string outputFileDirectoryPath = Path.GetDirectoryName(outputFilePath); if (outputFileDirectoryPath != null && outputFileDirectoryPath != outputPath && !Directory.Exists(outputFileDirectoryPath)) { Directory.CreateDirectory(outputFileDirectoryPath); } File.WriteAllText(outputFilePath, namedText.Text); } foreach (string nameToDelete in namesToDelete) { File.Delete(Path.Combine(outputPath, nameToDelete)); } } return(result); }