From f09ecd3bfdc5aeac3bced81ed551d85d77547d76 Mon Sep 17 00:00:00 2001 From: carlossanlop <1175054+carlossanlop@users.noreply.github.com> Date: Mon, 14 Mar 2022 22:54:08 -0700 Subject: [PATCH 1/3] PortToDocs: Add public method to collect files automatically, include method to allow collecting a file manually. --- src/PortToDocs/src/app/PortToDocs.cs | 1 + .../libraries/Docs/DocsCommentsContainer.cs | 69 +++++-------------- .../IntelliSenseXmlCommentsContainer.cs | 35 ++-------- src/PortToDocs/src/libraries/ToDocsPorter.cs | 65 ++++++++++++++++- .../tests/PortToDocs/PortToDocsTests.cs | 1 + 5 files changed, 87 insertions(+), 84 deletions(-) diff --git a/src/PortToDocs/src/app/PortToDocs.cs b/src/PortToDocs/src/app/PortToDocs.cs index aff8a31..2cc5588 100644 --- a/src/PortToDocs/src/app/PortToDocs.cs +++ b/src/PortToDocs/src/app/PortToDocs.cs @@ -11,6 +11,7 @@ public static void Main(string[] args) { Configuration config = Configuration.GetCLIArguments(args); ToDocsPorter porter = new(config); + porter.CollectFiles(); porter.Start(); } } diff --git a/src/PortToDocs/src/libraries/Docs/DocsCommentsContainer.cs b/src/PortToDocs/src/libraries/Docs/DocsCommentsContainer.cs index f087f91..a41424b 100644 --- a/src/PortToDocs/src/libraries/Docs/DocsCommentsContainer.cs +++ b/src/PortToDocs/src/libraries/Docs/DocsCommentsContainer.cs @@ -15,8 +15,6 @@ internal class DocsCommentsContainer { private Configuration Config { get; set; } - private XDocument? xDoc = null; - public readonly Dictionary Types = new(); public readonly Dictionary Members = new(); @@ -25,19 +23,6 @@ public DocsCommentsContainer(Configuration config) Config = config; } - public void CollectFiles() - { - Log.Info("Looking for Docs xml files..."); - - foreach (FileInfo fileInfo in EnumerateFiles()) - { - LoadFile(fileInfo); - } - - Log.Success("Finished looking for Docs xml files."); - Log.Line(); - } - public void Save() { if (!Config.Save) @@ -95,19 +80,7 @@ public void Save() } } - private bool HasAllowedDirName(DirectoryInfo dirInfo) - { - return !Configuration.ForbiddenBinSubdirectories.Contains(dirInfo.Name) && !dirInfo.Name.EndsWith(".Tests"); - } - - private bool HasAllowedFileName(FileInfo fileInfo) - { - return !fileInfo.Name.StartsWith("ns-") && - fileInfo.Name != "index.xml" && - fileInfo.Name != "_filter.xml"; - } - - private IEnumerable EnumerateFiles() + internal IEnumerable EnumerateFiles() { // Union avoids duplication var includedAssembliesAndNamespaces = Config.IncludedAssemblies.Union(Config.IncludedNamespaces); @@ -164,32 +137,14 @@ private IEnumerable EnumerateFiles() } } - private void LoadFile(FileInfo fileInfo) + internal void LoadDocsFile(XDocument xDoc, string filePath, Encoding encoding) { - Encoding? encoding = null; - try - { - var utf8NoBom = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false); - var utf8Bom = new UTF8Encoding(encoderShouldEmitUTF8Identifier: true); - using (StreamReader sr = new(fileInfo.FullName, utf8NoBom, detectEncodingFromByteOrderMarks: true)) - { - xDoc = XDocument.Load(sr); - encoding = sr.CurrentEncoding; - } - - } - catch (Exception ex) - { - Log.Error($"Failed to load '{fileInfo.FullName}'. {ex}"); - return; - } - - if (IsXmlMalformed(xDoc, fileInfo.FullName)) + if (IsXmlMalformed(xDoc, filePath)) { return; } - DocsType docsType = new DocsType(fileInfo.FullName, xDoc, xDoc.Root!, encoding); + DocsType docsType = new DocsType(filePath, xDoc, xDoc.Root!, encoding); bool add = false; bool addedAsInterface = false; @@ -246,13 +201,13 @@ private void LoadFile(FileInfo fileInfo) { foreach (XElement xeMember in xeMembers.Elements("Member")) { - DocsMember member = new DocsMember(fileInfo.FullName, docsType, xeMember); + DocsMember member = new DocsMember(filePath, docsType, xeMember); totalMembersAdded++; Members.TryAdd(member.DocId, member); // is it OK this encounters duplicates? } } - string message = $"Type '{docsType.DocId}' added with {totalMembersAdded} member(s) included: {fileInfo.FullName}"; + string message = $"Type '{docsType.DocId}' added with {totalMembersAdded} member(s) included: {filePath}"; if (addedAsInterface) { Log.Magenta("[Interface] - " + message); @@ -268,6 +223,18 @@ private void LoadFile(FileInfo fileInfo) } } + private bool HasAllowedDirName(DirectoryInfo dirInfo) + { + return !Configuration.ForbiddenBinSubdirectories.Contains(dirInfo.Name) && !dirInfo.Name.EndsWith(".Tests"); + } + + private bool HasAllowedFileName(FileInfo fileInfo) + { + return !fileInfo.Name.StartsWith("ns-") && + fileInfo.Name != "index.xml" && + fileInfo.Name != "_filter.xml"; + } + private bool IsXmlMalformed(XDocument? xDoc, string fileName) { if (xDoc == null) diff --git a/src/PortToDocs/src/libraries/IntelliSenseXml/IntelliSenseXmlCommentsContainer.cs b/src/PortToDocs/src/libraries/IntelliSenseXml/IntelliSenseXmlCommentsContainer.cs index 24a8058..3238cc3 100644 --- a/src/PortToDocs/src/libraries/IntelliSenseXml/IntelliSenseXmlCommentsContainer.cs +++ b/src/PortToDocs/src/libraries/IntelliSenseXml/IntelliSenseXmlCommentsContainer.cs @@ -36,8 +36,6 @@ internal class IntelliSenseXmlCommentsContainer { private Configuration Config { get; set; } - private XDocument? xDoc = null; - // The IntelliSense xml files do not separate types from members, like ECMA xml files do - Everything is a member. public Dictionary Members = new(); @@ -46,20 +44,7 @@ public IntelliSenseXmlCommentsContainer(Configuration config) Config = config; } - public void CollectFiles() - { - Log.Info("Looking for IntelliSense xml files..."); - - foreach (FileInfo fileInfo in EnumerateFiles()) - { - LoadFile(fileInfo, printSuccess: true); - } - - Log.Success("Finished looking for IntelliSense xml files."); - Log.Line(); - } - - private IEnumerable EnumerateFiles() + internal IEnumerable EnumerateFiles() { foreach (DirectoryInfo dirInfo in Config.DirsIntelliSense) { @@ -85,19 +70,9 @@ private IEnumerable EnumerateFiles() } } - private void LoadFile(FileInfo fileInfo, bool printSuccess) + internal void LoadIntellisenseXmlFile(XDocument xDoc, string filePath) { - try - { - xDoc = XDocument.Load(fileInfo.FullName); - } - catch (Exception ex) - { - Log.Error($"Failed to load '{fileInfo.FullName}'. {ex}"); - return; - } - - if (!TryGetAssemblyName(xDoc, fileInfo.FullName, out string? assembly)) + if (!TryGetAssemblyName(xDoc, filePath, out string? assembly)) { return; } @@ -124,9 +99,9 @@ private void LoadFile(FileInfo fileInfo, bool printSuccess) } } - if (printSuccess && totalAdded > 0) + if (totalAdded > 0) { - Log.Success($"{totalAdded} IntelliSense xml member(s) added from xml file '{fileInfo.FullName}'"); + Log.Success($"{totalAdded} IntelliSense xml member(s) added from xml file '{filePath}'"); } } diff --git a/src/PortToDocs/src/libraries/ToDocsPorter.cs b/src/PortToDocs/src/libraries/ToDocsPorter.cs index 1c1461b..3d1c88f 100644 --- a/src/PortToDocs/src/libraries/ToDocsPorter.cs +++ b/src/PortToDocs/src/libraries/ToDocsPorter.cs @@ -3,7 +3,9 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Text; using System.Xml.Linq; using ApiDocsSync.Libraries.Docs; using ApiDocsSync.Libraries.IntelliSenseXml; @@ -32,19 +34,76 @@ public ToDocsPorter(Configuration config) } - public void Start() + public void CollectFiles() { - IntelliSenseXmlComments.CollectFiles(); + Log.Info("Looking for IntelliSense xml files..."); + foreach (FileInfo fileInfo in IntelliSenseXmlComments.EnumerateFiles()) + { + XDocument? xDoc = null; + try + { + xDoc = XDocument.Load(fileInfo.FullName); + } + catch (Exception ex) + { + Log.Error($"Failed to load '{fileInfo.FullName}'. {ex}"); + } + + if (xDoc != null) + { + IntelliSenseXmlComments.LoadIntellisenseXmlFile(xDoc, fileInfo.FullName); + } + } + Log.Success("Finished looking for IntelliSense xml files."); + Log.Line(); + Log.Info("Looking for Docs xml files..."); + foreach (FileInfo fileInfo in DocsComments.EnumerateFiles()) + { + XDocument? xDoc = null; + Encoding? encoding = null; + try + { + var utf8NoBom = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false); + var utf8Bom = new UTF8Encoding(encoderShouldEmitUTF8Identifier: true); + using (StreamReader sr = new(fileInfo.FullName, utf8NoBom, detectEncodingFromByteOrderMarks: true)) + { + xDoc = XDocument.Load(sr); + encoding = sr.CurrentEncoding; + } + } + catch (Exception ex) + { + Log.Error($"Failed to load '{fileInfo.FullName}'. {ex}"); + } + + if (xDoc != null && encoding != null) + { + DocsComments.LoadDocsFile(xDoc, fileInfo.FullName, encoding); + } + } + Log.Success("Finished looking for Docs xml files."); + Log.Line(); + } + + public void LoadIntellisenseXmlFile(XDocument xDoc, string filePath) => + IntelliSenseXmlComments.LoadIntellisenseXmlFile(xDoc, filePath); + + public void LoadDocsFile(XDocument xDoc, string filePath, Encoding encoding) => + DocsComments.LoadDocsFile(xDoc, filePath, encoding); + + public void Start() + { if (!IntelliSenseXmlComments.Members.Any()) { Log.Error("No IntelliSense xml comments found."); + return; } - DocsComments.CollectFiles(); if (!DocsComments.Types.Any()) { Log.Error("No Docs Type APIs found."); + return; } PortMissingComments(); diff --git a/src/PortToDocs/tests/PortToDocs/PortToDocsTests.cs b/src/PortToDocs/tests/PortToDocs/PortToDocsTests.cs index 14e9b51..15d20f3 100644 --- a/src/PortToDocs/tests/PortToDocs/PortToDocsTests.cs +++ b/src/PortToDocs/tests/PortToDocs/PortToDocsTests.cs @@ -190,6 +190,7 @@ private static void PortToDocs( c.DirsIntelliSense.Add(new(Path.Join(targetDir, IntellisenseDir))); var porter = new ToDocsPorter(c); + porter.CollectFiles(); porter.Start(); Verify(targetDir); From 4ee9bab5a70d02f328679105e1c1b785f1bb7b48 Mon Sep 17 00:00:00 2001 From: carlossanlop <1175054+carlossanlop@users.noreply.github.com> Date: Mon, 14 Mar 2022 23:00:15 -0700 Subject: [PATCH 2/3] Apply some minor Roslyn suggestions. --- .../libraries/Docs/DocsCommentsContainer.cs | 30 +++++++------------ .../IntelliSenseXmlCommentsContainer.cs | 18 +++++------ 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/src/PortToDocs/src/libraries/Docs/DocsCommentsContainer.cs b/src/PortToDocs/src/libraries/Docs/DocsCommentsContainer.cs index a41424b..c2f1a28 100644 --- a/src/PortToDocs/src/libraries/Docs/DocsCommentsContainer.cs +++ b/src/PortToDocs/src/libraries/Docs/DocsCommentsContainer.cs @@ -18,10 +18,7 @@ internal class DocsCommentsContainer public readonly Dictionary Types = new(); public readonly Dictionary Members = new(); - public DocsCommentsContainer(Configuration config) - { - Config = config; - } + public DocsCommentsContainer(Configuration config) => Config = config; public void Save() { @@ -36,7 +33,7 @@ public void Save() } List savedFiles = new(); - foreach (var type in Types.Values.Where(x => x.Changed)) + foreach (DocsType type in Types.Values.Where(x => x.Changed)) { Log.Info(false, $"Saving changes for {type.FilePath} ... "); @@ -83,8 +80,8 @@ public void Save() internal IEnumerable EnumerateFiles() { // Union avoids duplication - var includedAssembliesAndNamespaces = Config.IncludedAssemblies.Union(Config.IncludedNamespaces); - var excludedAssembliesAndNamespaces = Config.ExcludedAssemblies.Union(Config.ExcludedNamespaces); + IEnumerable includedAssembliesAndNamespaces = Config.IncludedAssemblies.Union(Config.IncludedNamespaces); + IEnumerable excludedAssembliesAndNamespaces = Config.ExcludedAssemblies.Union(Config.ExcludedNamespaces); foreach (DirectoryInfo rootDir in Config.DirsDocsXml) { @@ -144,7 +141,7 @@ internal void LoadDocsFile(XDocument xDoc, string filePath, Encoding encoding) return; } - DocsType docsType = new DocsType(filePath, xDoc, xDoc.Root!, encoding); + DocsType docsType = new(filePath, xDoc, xDoc.Root!, encoding); bool add = false; bool addedAsInterface = false; @@ -163,7 +160,6 @@ internal void LoadDocsFile(XDocument xDoc, string filePath, Encoding encoding) // Interface files start with I, and have an 2nd alphabetic character addedAsInterface = docsType.Name.Length >= 2 && docsType.Name[0] == 'I' && docsType.Name[1] >= 'A' && docsType.Name[1] <= 'Z'; add |= addedAsInterface; - } bool containsAllowedAssembly = docsType.AssemblyInfos.Any(assemblyInfo => @@ -201,7 +197,7 @@ internal void LoadDocsFile(XDocument xDoc, string filePath, Encoding encoding) { foreach (XElement xeMember in xeMembers.Elements("Member")) { - DocsMember member = new DocsMember(filePath, docsType, xeMember); + DocsMember member = new(filePath, docsType, xeMember); totalMembersAdded++; Members.TryAdd(member.DocId, member); // is it OK this encounters duplicates? } @@ -223,19 +219,15 @@ internal void LoadDocsFile(XDocument xDoc, string filePath, Encoding encoding) } } - private bool HasAllowedDirName(DirectoryInfo dirInfo) - { - return !Configuration.ForbiddenBinSubdirectories.Contains(dirInfo.Name) && !dirInfo.Name.EndsWith(".Tests"); - } + private static bool HasAllowedDirName(DirectoryInfo dirInfo) => + !Configuration.ForbiddenBinSubdirectories.Contains(dirInfo.Name) && !dirInfo.Name.EndsWith(".Tests", StringComparison.InvariantCultureIgnoreCase); - private bool HasAllowedFileName(FileInfo fileInfo) - { - return !fileInfo.Name.StartsWith("ns-") && + private static bool HasAllowedFileName(FileInfo fileInfo) => + !fileInfo.Name.StartsWith("ns-") && fileInfo.Name != "index.xml" && fileInfo.Name != "_filter.xml"; - } - private bool IsXmlMalformed(XDocument? xDoc, string fileName) + private static bool IsXmlMalformed(XDocument? xDoc, string fileName) { if (xDoc == null) { diff --git a/src/PortToDocs/src/libraries/IntelliSenseXml/IntelliSenseXmlCommentsContainer.cs b/src/PortToDocs/src/libraries/IntelliSenseXml/IntelliSenseXmlCommentsContainer.cs index 3238cc3..1f92679 100644 --- a/src/PortToDocs/src/libraries/IntelliSenseXml/IntelliSenseXmlCommentsContainer.cs +++ b/src/PortToDocs/src/libraries/IntelliSenseXml/IntelliSenseXmlCommentsContainer.cs @@ -6,7 +6,6 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; -using System.Xml; using System.Xml.Linq; /* @@ -39,10 +38,7 @@ internal class IntelliSenseXmlCommentsContainer // The IntelliSense xml files do not separate types from members, like ECMA xml files do - Everything is a member. public Dictionary Members = new(); - public IntelliSenseXmlCommentsContainer(Configuration config) - { - Config = config; - } + public IntelliSenseXmlCommentsContainer(Configuration config) => Config = config; internal IEnumerable EnumerateFiles() { @@ -82,15 +78,15 @@ internal void LoadIntellisenseXmlFile(XDocument xDoc, string filePath) { foreach (XElement xeMember in xeMembers.Elements("member")) { - IntelliSenseXmlMember member = new IntelliSenseXmlMember(xeMember, assembly); + IntelliSenseXmlMember member = new(xeMember, assembly); - if (Config.IncludedAssemblies.Any(included => member.Assembly.StartsWith(included)) && - !Config.ExcludedAssemblies.Any(excluded => member.Assembly.StartsWith(excluded))) + if (Config.IncludedAssemblies.Any(included => member.Assembly.StartsWith(included, StringComparison.InvariantCultureIgnoreCase)) && + !Config.ExcludedAssemblies.Any(excluded => member.Assembly.StartsWith(excluded, StringComparison.InvariantCultureIgnoreCase))) { // No namespaces provided by the user means they want to port everything from that assembly if (!Config.IncludedNamespaces.Any() || - (Config.IncludedNamespaces.Any(included => member.Namespace.StartsWith(included)) && - !Config.ExcludedNamespaces.Any(excluded => member.Namespace.StartsWith(excluded)))) + (Config.IncludedNamespaces.Any(included => member.Namespace.StartsWith(included, StringComparison.InvariantCultureIgnoreCase)) && + !Config.ExcludedNamespaces.Any(excluded => member.Namespace.StartsWith(excluded, StringComparison.InvariantCultureIgnoreCase)))) { totalAdded++; Members.TryAdd(member.Name, member); // is it OK this encounters duplicates? @@ -106,7 +102,7 @@ internal void LoadIntellisenseXmlFile(XDocument xDoc, string filePath) } // Verifies the file is properly formed while attempting to retrieve the assembly name. - private bool TryGetAssemblyName(XDocument? xDoc, string fileName, [NotNullWhen(returnValue: true)] out string? assembly) + private static bool TryGetAssemblyName(XDocument? xDoc, string fileName, [NotNullWhen(returnValue: true)] out string? assembly) { assembly = null; From 7d6b8ea137b3ec32ba851449f6ec21c8f2a577a0 Mon Sep 17 00:00:00 2001 From: carlossanlop <1175054+carlossanlop@users.noreply.github.com> Date: Mon, 14 Mar 2022 23:02:18 -0700 Subject: [PATCH 3/3] Rename method in tests that ports from file to file. --- .../tests/PortToDocs/PortToDocsTests.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/PortToDocs/tests/PortToDocs/PortToDocsTests.cs b/src/PortToDocs/tests/PortToDocs/PortToDocsTests.cs index 15d20f3..49605df 100644 --- a/src/PortToDocs/tests/PortToDocs/PortToDocsTests.cs +++ b/src/PortToDocs/tests/PortToDocs/PortToDocsTests.cs @@ -19,27 +19,27 @@ public PortToDocsTests(ITestOutputHelper output) : base(output) // Verifies the basic case of porting all regular fields. public void Port_Basic() { - PortToDocs("Basic", GetConfiguration()); + PortToDocsWithFileSystem("Basic", GetConfiguration()); } [Fact] public void Port_DontAddMissingRemarks() { - PortToDocs("DontAddMissingRemarks", GetConfiguration()); + PortToDocsWithFileSystem("DontAddMissingRemarks", GetConfiguration()); } [Fact] // Verifies porting of APIs living in namespaces whose name match their assembly. public void Port_AssemblyAndNamespaceSame() { - PortToDocs("AssemblyAndNamespaceSame", GetConfiguration()); + PortToDocsWithFileSystem("AssemblyAndNamespaceSame", GetConfiguration()); } [Fact] // Verifies porting of APIs living in namespaces whose name does not match their assembly. public void Port_AssemblyAndNamespaceDifferent() { - PortToDocs("AssemblyAndNamespaceDifferent", + PortToDocsWithFileSystem("AssemblyAndNamespaceDifferent", GetConfiguration(), namespaceNames: new[] { TestData.TestNamespace }); } @@ -51,7 +51,7 @@ public void Port_AssemblyAndNamespaceDifferent() public void Port_Remarks_NoEII_NoInterfaceRemarks() { Configuration c = GetConfiguration(skipInterfaceImplementations: true, skipInterfaceRemarks: true); - PortToDocs("Remarks_NoEII_NoInterfaceRemarks", c); + PortToDocsWithFileSystem("Remarks_NoEII_NoInterfaceRemarks", c); } [Fact] @@ -61,7 +61,7 @@ public void Port_Remarks_NoEII_NoInterfaceRemarks() public void Port_Remarks_WithEII_WithInterfaceRemarks() { Configuration c = GetConfiguration(skipInterfaceImplementations: false, skipInterfaceRemarks: false); - PortToDocs("Remarks_WithEII_WithInterfaceRemarks", c); + PortToDocsWithFileSystem("Remarks_WithEII_WithInterfaceRemarks", c); } [Fact] @@ -71,14 +71,14 @@ public void Port_Remarks_WithEII_WithInterfaceRemarks() public void Port_Remarks_WithEII_NoInterfaceRemarks() { Configuration c = GetConfiguration(skipInterfaceImplementations: false, skipInterfaceRemarks: true); - PortToDocs("Remarks_WithEII_NoInterfaceRemarks", c); + PortToDocsWithFileSystem("Remarks_WithEII_NoInterfaceRemarks", c); } [Fact] // Verifies that new exceptions are ported. public void Port_Exceptions() { - PortToDocs("Exceptions", GetConfiguration()); + PortToDocsWithFileSystem("Exceptions", GetConfiguration()); } [Fact] @@ -87,14 +87,14 @@ public void Port_Exceptions() public void Port_Exception_ExistingCref() { Configuration c = GetConfiguration(portExceptionsExisting: true, exceptionCollisionThreshold: 60); - PortToDocs("Exception_ExistingCref", c); + PortToDocsWithFileSystem("Exception_ExistingCref", c); } [Fact] // Avoid porting enum field remarks public void Port_EnumRemarks() { - PortToDocs("EnumRemarks", GetConfiguration()); + PortToDocsWithFileSystem("EnumRemarks", GetConfiguration()); } [Fact] @@ -102,7 +102,7 @@ public void Port_EnumRemarks() // The parent type is located in a different assembly. public void Port_InheritDoc() { - PortToDocs("InheritDoc", + PortToDocsWithFileSystem("InheritDoc", GetConfiguration(), assemblyNames: new[] { TestData.TestAssembly, "System" }); } @@ -158,7 +158,7 @@ private static Configuration GetConfiguration( SkipInterfaceRemarks = skipInterfaceRemarks }; - private static void PortToDocs( + private static void PortToDocsWithFileSystem( string testName, Configuration c, string[] assemblyNames = null,