diff --git a/XmlSchemaClassGenerator.Console/Program.cs b/XmlSchemaClassGenerator.Console/Program.cs index a9e4121c..36716143 100644 --- a/XmlSchemaClassGenerator.Console/Program.cs +++ b/XmlSchemaClassGenerator.Console/Program.cs @@ -246,7 +246,7 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l generator.NamingProvider = new SubstituteNamingProvider(nameSubstituteMap); } - generator.CommentLanguages.AddRange(commentLanguages); + generator.CommentLanguages.UnionWith(commentLanguages); if (pclCompatible) { diff --git a/XmlSchemaClassGenerator.Tests/Compiler.cs b/XmlSchemaClassGenerator.Tests/Compiler.cs index 002c78f9..3d424797 100644 --- a/XmlSchemaClassGenerator.Tests/Compiler.cs +++ b/XmlSchemaClassGenerator.Tests/Compiler.cs @@ -122,7 +122,7 @@ public static Assembly GenerateFiles(string name, IEnumerable files, Gen }; gen.CommentLanguages.Clear(); - gen.CommentLanguages.AddRange(generatorPrototype.CommentLanguages); + gen.CommentLanguages.UnionWith(generatorPrototype.CommentLanguages); output.Configuration = gen.Configuration; diff --git a/XmlSchemaClassGenerator.Tests/DocumentationTests.cs b/XmlSchemaClassGenerator.Tests/DocumentationTests.cs new file mode 100644 index 00000000..58269075 --- /dev/null +++ b/XmlSchemaClassGenerator.Tests/DocumentationTests.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml.Schema; + +using Xunit; + +namespace XmlSchemaClassGenerator.Tests; + +public sealed class DocumentationTests +{ + static DocumentationTests() => Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + + private static IEnumerable ConvertXml(string xsd, Generator generatorPrototype) + { + var writer = new MemoryOutputWriter(); + + var gen = new Generator + { + OutputWriter = writer, + Version = new("Tests", "1.0.0.1"), + NamespaceProvider = generatorPrototype.NamespaceProvider, + //DataAnnotationMode = generatorPrototype.DataAnnotationMode, + GenerateDescriptionAttribute = generatorPrototype.GenerateDescriptionAttribute + }; + + var set = new XmlSchemaSet(); + + using (var stringReader = new StringReader(xsd)) + { + var schema = XmlSchema.Read + ( + stringReader, + (_, e) => throw new InvalidOperationException($"{e.Severity}: {e.Message}", e.Exception) + ); + + ArgumentNullException.ThrowIfNull(schema); + set.Add(schema); + } + + gen.Generate(set); + + return writer.Content; + } + + [Fact] + public void TestSummaryDoc() + { + const string xsd = """ + + + + + + Заголовок конверта. + Информация приложения + + + + + Тип программного обеспечения + + + + + Версия программного + обеспечения + + + + + Тип сообщения + + + + + + """; + + var code = string.Join + ( + "\r\n", + ConvertXml(xsd, new() {NamespacePrefix = "Test"}) + .Single() + .Split(new[] {"\r\n", "\r", "\n"}, StringSplitOptions.TrimEntries) + ); + + Assert.Contains + ( + "/// \r\n/// Заголовок конверта.\r\n/// Информация приложения\r\n/// ", + code, + StringComparison.Ordinal + ); + + Assert.Contains + ( + "/// \r\n/// Тип программного обеспечения\r\n/// ", + code, + StringComparison.Ordinal + ); + + Assert.Contains + ( + "/// \r\n/// Версия программного\r\n/// обеспечения\r\n/// ", + code, + StringComparison.Ordinal + ); + + Assert.Contains + ( + "/// \r\n/// Тип сообщения\r\n/// ", + code, + StringComparison.Ordinal + ); + } + + [Fact] + public void TestDescriptionAttributeValue() + { + const string xsd = """ + + + + + + Заголовок конверта. + Информация приложения + + + + + Тип программного обеспечения + + + + + Версия программного + обеспечения + + + + + Тип сообщения + + + + + + """; + + var code = ConvertXml(xsd, new() {NamespacePrefix = "Test", GenerateDescriptionAttribute = true}) + .Single(); + + Assert.Contains + ( + """[System.ComponentModel.DescriptionAttribute("Заголовок конверта. Информация приложения")]""", + code, + StringComparison.Ordinal + ); + + Assert.Contains + ( + """[System.ComponentModel.DescriptionAttribute("Тип программного обеспечения")]""", + code, + StringComparison.Ordinal + ); + + Assert.Contains + ( + """[System.ComponentModel.DescriptionAttribute("Версия программного обеспечения")]""", + code, + StringComparison.Ordinal + ); + + Assert.Contains + ( + """[System.ComponentModel.DescriptionAttribute("Тип сообщения")]""", + code, + StringComparison.Ordinal + ); + } +} \ No newline at end of file diff --git a/XmlSchemaClassGenerator.Tests/XmlTests.cs b/XmlSchemaClassGenerator.Tests/XmlTests.cs index 4edee63a..f9f0c47c 100644 --- a/XmlSchemaClassGenerator.Tests/XmlTests.cs +++ b/XmlSchemaClassGenerator.Tests/XmlTests.cs @@ -69,7 +69,7 @@ private static IEnumerable ConvertXml(string name, IEnumerable x }; gen.CommentLanguages.Clear(); - gen.CommentLanguages.AddRange(generatorPrototype.CommentLanguages); + gen.CommentLanguages.UnionWith(generatorPrototype.CommentLanguages); var set = new XmlSchemaSet(); diff --git a/XmlSchemaClassGenerator/Generator.cs b/XmlSchemaClassGenerator/Generator.cs index 89cad4e8..527324a0 100644 --- a/XmlSchemaClassGenerator/Generator.cs +++ b/XmlSchemaClassGenerator/Generator.cs @@ -277,7 +277,7 @@ public bool CompactTypeNames set { _configuration.CompactTypeNames = value; } } - public List CommentLanguages + public HashSet CommentLanguages { get { return _configuration.CommentLanguages; } } diff --git a/XmlSchemaClassGenerator/GeneratorConfiguration.cs b/XmlSchemaClassGenerator/GeneratorConfiguration.cs index add6a8cf..ef322630 100644 --- a/XmlSchemaClassGenerator/GeneratorConfiguration.cs +++ b/XmlSchemaClassGenerator/GeneratorConfiguration.cs @@ -291,7 +291,7 @@ public void WriteLog(string message) /// /// The language identifiers comments will be generated for, e.g. "en", "de-DE". /// - public List CommentLanguages { get; } = new List(); + public HashSet CommentLanguages { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); /// /// Create unique type names across all namespaces. See https://github.com/mganss/XmlSchemaClassGenerator/issues/240 diff --git a/XmlSchemaClassGenerator/ModelBuilder.cs b/XmlSchemaClassGenerator/ModelBuilder.cs index 0429ff1d..5eba9544 100644 --- a/XmlSchemaClassGenerator/ModelBuilder.cs +++ b/XmlSchemaClassGenerator/ModelBuilder.cs @@ -1078,7 +1078,7 @@ public static List GetDocumentation(XmlSchemaAnnotated annot return annotated.Annotation == null ? new List() : annotated.Annotation.Items.OfType() .Where(d => d.Markup?.Length > 0) - .Select(d => d.Markup.Select(m => new DocumentationModel { Language = d.Language, Text = new XText($"{m.Name}: {m.InnerText}").ToString() })) + .Select(d => d.Markup.Select(m => new DocumentationModel { Language = d.Language, Text = m.Value })) .SelectMany(d => d) .Where(d => !string.IsNullOrEmpty(d.Text)) .ToList(); diff --git a/XmlSchemaClassGenerator/TypeModel.cs b/XmlSchemaClassGenerator/TypeModel.cs index 16e353b2..5e667f17 100644 --- a/XmlSchemaClassGenerator/TypeModel.cs +++ b/XmlSchemaClassGenerator/TypeModel.cs @@ -10,6 +10,7 @@ using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; +using static System.Net.Mime.MediaTypeNames; namespace XmlSchemaClassGenerator { @@ -1401,43 +1402,64 @@ protected CodeTypeReference NullableTypeRef(CodeTypeReference typeReference) } public static bool DisableComments { get; set; } - protected IEnumerable GetComments(IList docs) + protected IEnumerable GetComments(IReadOnlyList docs) { if (DisableComments || docs.Count == 0) yield break; yield return new CodeCommentStatement("", true); - foreach (var doc in docs - .Where(d => string.IsNullOrEmpty(d.Language) || Configuration.CommentLanguages.Exists(l => d.Language.StartsWith(l, StringComparison.OrdinalIgnoreCase))) - .OrderBy(d => d.Language)) + foreach (var doc in docs.Where + ( + d => !string.IsNullOrWhiteSpace(d.Text) + && (string.IsNullOrEmpty(d.Language) + || Configuration.CommentLanguages.Count is 0 + || Configuration.CommentLanguages.Contains(d.Language) + || Configuration.CommentLanguages + .Any(l => d.Language.StartsWith(l, StringComparison.OrdinalIgnoreCase))) + ) + .OrderBy(d => d.Language)) { - var text = doc.Text; - var comment = $"{CodeUtilities.NormalizeNewlines(text).Trim()}"; - yield return new CodeCommentStatement(comment, true); + var text = doc.Text; + var comment = $"{CodeUtilities.NormalizeNewlines(text).Trim()}"; + + yield return new(comment, true); } yield return new CodeCommentStatement("", true); } - protected void AddDescription(CodeAttributeDeclarationCollection attributes, IEnumerable docs) + protected void AddDescription(CodeAttributeDeclarationCollection attributes, IReadOnlyList docs) { - if (!Configuration.GenerateDescriptionAttribute || DisableComments || !docs.Any()) return; + if (!Configuration.GenerateDescriptionAttribute || DisableComments || docs.Count is 0) return; - var doc = GetSingleDoc(docs.Where(d => string.IsNullOrEmpty(d.Language) || Configuration.CommentLanguages.Exists(l => d.Language.StartsWith(l, StringComparison.OrdinalIgnoreCase)))); + var docText = GetSingleDoc(docs); - if (doc != null) + if (string.IsNullOrWhiteSpace(docText) is false) { - var descriptionAttribute = AttributeDecl(new CodeAttributeArgument(new CodePrimitiveExpression(Regex.Replace(doc.Text, @"\s+", " ").Trim()))); + var descriptionAttribute = AttributeDecl(new CodeAttributeArgument(new CodePrimitiveExpression(Regex.Replace(docText, @"\s+", " ").Trim()))); attributes.Add(descriptionAttribute); } } - private static DocumentationModel GetSingleDoc(IEnumerable docs) - { - return docs.Count() == 1 ? docs.Single() - : docs.FirstOrDefault(d => string.IsNullOrEmpty(d.Language) || d.Language.StartsWith(English, StringComparison.OrdinalIgnoreCase)) - ?? docs.FirstOrDefault(); - } + private string GetSingleDoc(IReadOnlyList docs) => string.Join + ( + " ", + docs.Where + ( + d => !string.IsNullOrWhiteSpace(d.Text) + && (string.IsNullOrEmpty(d.Language) + || Configuration.CommentLanguages.Count is 0 + || Configuration.CommentLanguages.Contains(d.Language) + || Configuration.CommentLanguages + .Any(l => d.Language.StartsWith(l, StringComparison.OrdinalIgnoreCase))) + ) + .Where + ( + d => string.IsNullOrEmpty(d.Language) + || d.Language.StartsWith(English, StringComparison.OrdinalIgnoreCase) + ) + .Select(x => x.Text) + ); } }