Skip to content

Plaintext review #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Apr 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
294dd63
PlainText review updates
YuriyDurov Apr 6, 2025
036fbc4
Update PlainTextRenderer signature
a-gubskiy Apr 7, 2025
369c4f9
Update TestDocumentationElement
a-gubskiy Apr 7, 2025
18b1ce0
Update tests
a-gubskiy Apr 7, 2025
6b9b34f
Hide MemberIdentifier
a-gubskiy Apr 7, 2025
b3bbb7a
Refactor RenderTextNode method to be static and move it within the Pl…
a-gubskiy Apr 9, 2025
e04dfd7
Enhance MemberIdentifier constructor with validation for cref input
a-gubskiy Apr 9, 2025
976aa2c
Remove unnecessary blank lines in InheritanceResolver.cs
a-gubskiy Apr 9, 2025
4ce81da
Add null checks for entity and property documentation in EntitiesComm…
a-gubskiy Apr 9, 2025
40bef9c
Add null checks for documentation elements in EntityTypeBuilderExtens…
a-gubskiy Apr 9, 2025
10ec123
Add null checks for documentation elements in PropertyBuilderExtensions
a-gubskiy Apr 9, 2025
e16de47
Refactor null checks to use 'is null' pattern in various extensions a…
a-gubskiy Apr 9, 2025
713cc39
Rename EntitiesCommentConfigurator to EntitiesDocumentationConfigurat…
a-gubskiy Apr 9, 2025
352d901
Enhance PlainTextRendererEndToEndTests with null checks and additiona…
a-gubskiy Apr 9, 2025
17735c1
Add null checks in tests
a-gubskiy Apr 9, 2025
fe2dc0d
Refactor PlainTextRenderer to handle unreachable code with an exception
a-gubskiy Apr 9, 2025
2a9d199
Rename parameter 'cref' to 'value' in MemberIdentifier for clarity an…
a-gubskiy Apr 9, 2025
ac31a30
Update tests/Render/BitzArt.XDoc.PlainText.Tests/PlainTextRendererEnd…
a-gubskiy Apr 9, 2025
b5d727c
Update rendering logic.
a-gubskiy Apr 9, 2025
d8c3f95
Update src/EntityFrameworkCore/BitzArt.XDoc.EntityFrameworkCore/Entit…
a-gubskiy Apr 9, 2025
1d6936e
Add exception description
a-gubskiy Apr 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public abstract class DocumentationElement : IDocumentationElement
/// </summary>
/// <param name="source">The source of the documentation.</param>
/// <param name="node">The XML node that contains the documentation.</param>
protected DocumentationElement(XDoc source, XmlNode? node)
internal DocumentationElement(XDoc source, XmlNode? node)
{
Source = source;
Node = node;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ namespace BitzArt.XDoc;
/// Configures XML documentation comments for Entity Framework Core entities and their properties.
/// </summary>
[PublicAPI]
public class EntitiesCommentConfigurator
public class EntitiesDocumentationConfigurator
{
private readonly XDoc _xDoc;

/// <summary>
/// Default constructor.
/// </summary>
public EntitiesCommentConfigurator(XDoc xDoc)
public EntitiesDocumentationConfigurator(XDoc xDoc)
{
_xDoc = xDoc;
}
Expand All @@ -29,7 +29,14 @@ public void ConfigureComments(ModelBuilder modelBuilder)

foreach (var entityType in entityTypes)
{
var entityComment = _xDoc.Get(entityType.ClrType).ToPlainText();
var typeDocumentation = _xDoc.Get(entityType.ClrType);

if (typeDocumentation is null)
{
continue;
}

var entityComment = typeDocumentation.ToPlainText();

// For owned entities, we don't set the comment on the entity itself
// But we will set the comment on the properties
Expand All @@ -55,12 +62,19 @@ public void ConfigureComments(ModelBuilder modelBuilder)

var propertyInfo = entityType.ClrType.GetProperty(property.Name);

if (propertyInfo == null)
if (propertyInfo is null)
{
continue;
}

var propertyDocumentation = _xDoc.Get(propertyInfo);

if (propertyDocumentation is null)
{
return;
continue;
}

var propertyComment = _xDoc.Get(propertyInfo).ToPlainText();
var propertyComment = propertyDocumentation.ToPlainText();

property.SetComment(propertyComment);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,14 @@ public static EntityTypeBuilder<TEntity> HasPropertyComment<TEntity, TProperty>(
where TEntity : class
where TCommentTargetEntity : class
{
var comment = xdoc.Get(commentTargetPropertyExpression).ToPlainText();
var documentationElement = xdoc.Get(commentTargetPropertyExpression);

if (documentationElement is null)
{
return entityTypeBuilder;
}

var comment = documentationElement.ToPlainText();

return entityTypeBuilder.HasPropertyComment(propertyExpression, comment);
}
Expand Down Expand Up @@ -96,7 +103,14 @@ public static EntityTypeBuilder<TEntity> HasPropertyComment<TEntity>(
throw new InvalidOperationException("The property name is ambiguous.");
}

var comment = xdoc.Get(memberInfo.First()).ToPlainText();
var documentationElement = xdoc.Get(memberInfo.First());

if (documentationElement is null)
{
return entityTypeBuilder;
}

var comment = documentationElement.ToPlainText();

entityTypeBuilder.Property(propertyName).HasComment(comment);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,15 @@ public static PropertyBuilder HasComment<TCommentTargetEntity, TCommentTargetPro
Expression<Func<TCommentTargetEntity, TCommentTargetProperty>> commentTargetPropertyExpression)
where TCommentTargetEntity : class
{
var comment = xdoc.Get(commentTargetPropertyExpression).ToPlainText();
var documentationElement = xdoc.Get(commentTargetPropertyExpression);

if (documentationElement is null)
{
return propertyBuilder;
}

var comment = documentationElement.ToPlainText();

return propertyBuilder.HasComment(comment);
}

Expand All @@ -51,7 +58,14 @@ public static PropertyBuilder<TProperty> HasComment<TProperty, TCommentTargetEnt
Expression<Func<TCommentTargetEntity, TCommentTargetProperty>> commentTargetPropertyExpression)
where TCommentTargetEntity : class
{
var comment = xdoc.Get(commentTargetPropertyExpression).ToPlainText();
var documentationElement = xdoc.Get(commentTargetPropertyExpression);

if (documentationElement is null)
{
return propertyBuilder;
}

var comment = documentationElement.ToPlainText();

return propertyBuilder.HasComment(comment);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<RootNamespace>BitzArt.XDoc</RootNamespace>
<RootNamespace>BitzArt.XDoc.PlainText</RootNamespace>

<PackageId>BitzArt.XDoc.PlainText</PackageId>
<Authors>BitzArt</Authors>
Expand Down
15 changes: 9 additions & 6 deletions src/Render/BitzArt.XDoc.PlainText/InheritanceResolver.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Reflection;

namespace BitzArt.XDoc;
namespace BitzArt.XDoc.PlainText;

/// <summary>
/// Direct inheritance resolver (<c>&lt;inheritdoc/&gt;</c>)
Expand Down Expand Up @@ -44,7 +44,7 @@ internal static class InheritanceResolver
{
return found;
}

var result = FindTargetMember(immediateInterface, sourceMember);

if (result is not null)
Expand All @@ -63,7 +63,6 @@ internal static class InheritanceResolver
return result;
}
}


return null;
}
Expand All @@ -89,9 +88,13 @@ [.. methodInfo.GetParameters().Select(p => p.ParameterType)]),

private static IEnumerable<Type> GetImmediateInterfaces(Type type)
{
var inheritedInterfaces = type.GetInterfaces().SelectMany(i => i.GetInterfaces()).ToList();
inheritedInterfaces.AddRange(type.BaseType?.GetInterfaces() ?? []);
var inheritedInterfaces = type
.GetInterfaces()
.SelectMany(i => i.GetInterfaces())
.Union(type.BaseType?.GetInterfaces() ?? []);

var result = type.GetInterfaces().Except(inheritedInterfaces);

return type.GetInterfaces().Except(inheritedInterfaces);
return result;
}
}
45 changes: 25 additions & 20 deletions src/Render/BitzArt.XDoc.PlainText/MemberIdentifier.cs
Original file line number Diff line number Diff line change
@@ -1,38 +1,43 @@
using JetBrains.Annotations;

namespace BitzArt.XDoc;

namespace BitzArt.XDoc.PlainText;

/// <summary>
/// Represents and parses XML documentation references (crefs) for types and members.
/// Handles type references (T:), method references (M:), property references (P:), and field references (F:).
/// Represents an identifier for types and members in XML documentation comments.
/// </summary>
[PublicAPI]
public record MemberIdentifier
internal record MemberIdentifier
{
/// <summary>
/// Initializes a new instance of the <see cref="MemberIdentifier"/> class by parsing a cref string.
/// Initializes a new instance of the <see cref="MemberIdentifier"/> class by parsing the given string.
/// </summary>
/// <param name="cref">The cref string to parse (e.g., "T:Namespace.TypeName" or "M:Namespace.TypeName.MethodName").</param>
/// <param name="value">The cref string to parse (e.g., "T:Namespace.TypeName" or "M:Namespace.TypeName.MethodName").</param>
/// <exception cref="ArgumentException">Thrown when the cref format is invalid.</exception>
public MemberIdentifier(string cref)
private MemberIdentifier(string value)
{
Prefix = cref[..2];
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException("Cref cannot be null or empty", nameof(value));
}

if (value.Length < 3 || value[1] != ':')
{
throw new ArgumentException($"Invalid cref format: {value}", nameof(value));
}

Prefix = value[..2];

var lastIndexOf = cref.LastIndexOf('.');
var lastIndexOf = value.LastIndexOf('.');

switch (Prefix)
{
case "T:":
Type = cref.Substring(2, cref.Length - 2);
Type = value.Substring(2, value.Length - 2);
Member = null;
break;
case "M:" or "P:" or "F:":
Type = cref.Substring(2, lastIndexOf - 2);
Member = cref.Substring(lastIndexOf + 1, cref.Length - lastIndexOf - 1);
Type = value.Substring(2, lastIndexOf - 2);
Member = value.Substring(lastIndexOf + 1, value.Length - lastIndexOf - 1);
break;
default:
throw new ArgumentException($"Invalid cref: {cref}");
throw new ArgumentException($"Invalid value: {value}");
}

var typeLastIndexOf = Type.LastIndexOf('.');
Expand Down Expand Up @@ -76,19 +81,19 @@ public MemberIdentifier(string cref)
/// Formats the identifier back into a valid cref string.
/// </summary>
/// <returns>A string that represents the current object.</returns>
public override string ToString() => $"{Prefix}{Type}{(Member != null ? "." + Member : string.Empty)}";
public override string ToString() => $"{Prefix}{Type}{(Member is not null ? "." + Member : string.Empty)}";

/// <summary>
/// Attempts to create a <see cref="MemberIdentifier"/> from a string value.
/// </summary>
/// <param name="value">The cref string to parse.</param>
/// <param name="cref">When this method returns, contains the created <see cref="MemberIdentifier"/> if successful; otherwise, null.</param>
/// <returns>true if the creation was successful; otherwise, false.</returns>
public static bool TryCreate(string? value, out MemberIdentifier? cref)
public static bool TryCreate(string value, out MemberIdentifier? cref)
{
try
{
cref = new MemberIdentifier(value!);
cref = new MemberIdentifier(value);
}
catch
{
Expand Down
Loading