Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidVollmers committed Jun 22, 2024
1 parent f6106ea commit 7a1aac9
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 35 deletions.
76 changes: 44 additions & 32 deletions src/Doki.Extensions/DocumentationRootExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,55 @@

public static class DocumentationRootExtensions
{
public static DocumentationObject? TryGetParent(this DocumentationRoot root, DocumentationObject child)
public static T? TryGetParent<T>(this DocumentationRoot root, DocumentationObject child)
where T : DocumentationObject
{
ArgumentNullException.ThrowIfNull(root);
ArgumentNullException.ThrowIfNull(child);

return child.Parent ?? SearchParent(root, child);
if (child.Parent is T t) return t;

return SearchParent<T>(root, child, root);
}

private static DocumentationObject? SearchParent(DocumentationObject from, DocumentationObject to)
private static T? SearchParent<T>(DocumentationObject from, DocumentationObject to,
DocumentationObject subject) where T : DocumentationObject
{
if (from == to) return from;
if (from == to)
{
if (subject is T t) return t;

return null;
}

switch (from)
{
case DocumentationRoot root: return SearchParentIn(root.Assemblies, to);
case DocumentationRoot root: return SearchParentIn<T>(root.Assemblies, to, root);
case AssemblyDocumentation assemblyDocumentation:
return SearchParentIn(assemblyDocumentation.Namespaces, to);
case NamespaceDocumentation namespaceDocumentation: return SearchParentIn(namespaceDocumentation.Types, to);
return SearchParentIn<T>(assemblyDocumentation.Namespaces, to, assemblyDocumentation);
case NamespaceDocumentation namespaceDocumentation:
return SearchParentIn<T>(namespaceDocumentation.Types, to, namespaceDocumentation);
case TypeDocumentation typeDocumentation:
{
var constructor = SearchParentIn(typeDocumentation.Constructors, to);
var constructor = SearchParentIn<T>(typeDocumentation.Constructors, to, typeDocumentation);
if (constructor != null) return constructor;

var method = SearchParentIn(typeDocumentation.Methods, to);
var method = SearchParentIn<T>(typeDocumentation.Methods, to, typeDocumentation);
if (method != null) return method;

var property = SearchParentIn(typeDocumentation.Properties, to);
var property = SearchParentIn<T>(typeDocumentation.Properties, to, typeDocumentation);
if (property != null) return property;

var field = SearchParentIn(typeDocumentation.Fields, to);
var field = SearchParentIn<T>(typeDocumentation.Fields, to, typeDocumentation);
if (field != null) return field;

var interfaceDocumentation = SearchParentIn(typeDocumentation.Interfaces, to);
var interfaceDocumentation = SearchParentIn<T>(typeDocumentation.Interfaces, to, typeDocumentation);
if (interfaceDocumentation != null) return interfaceDocumentation;

var derivedType = SearchParentIn(typeDocumentation.DerivedTypes, to);
var derivedType = SearchParentIn<T>(typeDocumentation.DerivedTypes, to, typeDocumentation);
if (derivedType != null) return derivedType;

var result = SearchParentInTypeDocumentationReference(typeDocumentation, to);
var result = SearchParentInTypeDocumentationReference<T>(typeDocumentation, to);
if (result != null) return result;

break;
Expand All @@ -49,32 +59,33 @@ public static class DocumentationRootExtensions
{
if (genericTypeArgumentDocumentation.Description != null)
{
var description = SearchParent(genericTypeArgumentDocumentation.Description, to);
var description = SearchParent<T>(genericTypeArgumentDocumentation.Description, to,
genericTypeArgumentDocumentation);
if (description != null) return description;
}

var result = SearchParentInTypeDocumentationReference(genericTypeArgumentDocumentation, to);
var result = SearchParentInTypeDocumentationReference<T>(genericTypeArgumentDocumentation, to);
if (result != null) return result;

break;
}
case TypeDocumentationReference typeDocumentationReference:
{
var result = SearchParentInTypeDocumentationReference(typeDocumentationReference, to);
var result = SearchParentInTypeDocumentationReference<T>(typeDocumentationReference, to);
if (result != null) return result;

break;
}
case MemberDocumentation memberDocumentation:
{
var result = SearchParentInMemberDocumentation(memberDocumentation, to);
var result = SearchParentInMemberDocumentation<T>(memberDocumentation, to);
if (result != null) return result;

break;
}
case XmlDocumentation xmlDocumentation:
{
var result = SearchParentIn(xmlDocumentation.Contents, to);
var result = SearchParentIn<T>(xmlDocumentation.Contents, to, xmlDocumentation);
if (result != null) return result;

break;
Expand All @@ -84,35 +95,36 @@ public static class DocumentationRootExtensions
return null;
}

private static DocumentationObject? SearchParentInTypeDocumentationReference(
TypeDocumentationReference typeDocumentationReference, DocumentationObject to)
private static T? SearchParentInTypeDocumentationReference<T>(
TypeDocumentationReference typeDocumentationReference, DocumentationObject to) where T : DocumentationObject
{
if (typeDocumentationReference.BaseType != null)
{
var baseType = SearchParent(typeDocumentationReference.BaseType, to);
var baseType = SearchParent<T>(typeDocumentationReference.BaseType, to, typeDocumentationReference);
if (baseType != null) return baseType;
}

var genericArgument = SearchParentIn(typeDocumentationReference.GenericArguments, to);
return genericArgument ?? SearchParentInMemberDocumentation(typeDocumentationReference, to);
var genericArgument =
SearchParentIn<T>(typeDocumentationReference.GenericArguments, to, typeDocumentationReference);
return genericArgument ?? SearchParentInMemberDocumentation<T>(typeDocumentationReference, to);
}

private static DocumentationObject? SearchParentInMemberDocumentation(MemberDocumentation memberDocumentation,
DocumentationObject to)
private static T? SearchParentInMemberDocumentation<T>(MemberDocumentation memberDocumentation,
DocumentationObject to) where T : DocumentationObject
{
var summary = SearchParentIn(memberDocumentation.Summaries, to);
var summary = SearchParentIn<T>(memberDocumentation.Summaries, to, memberDocumentation);
if (summary != null) return summary;

var remarks = SearchParentIn(memberDocumentation.Remarks, to);
var remarks = SearchParentIn<T>(memberDocumentation.Remarks, to, memberDocumentation);
if (remarks != null) return remarks;

var example = SearchParentIn(memberDocumentation.Examples, to);
var example = SearchParentIn<T>(memberDocumentation.Examples, to, memberDocumentation);
return example;
}

private static DocumentationObject? SearchParentIn(IEnumerable<DocumentationObject> children,
DocumentationObject to)
private static T? SearchParentIn<T>(IEnumerable<DocumentationObject> children,
DocumentationObject to, DocumentationObject subject) where T : DocumentationObject
{
return children.Select(child => SearchParent(child, to)).OfType<DocumentationObject>().FirstOrDefault();
return children.Select(child => SearchParent<T>(child, to, subject)).FirstOrDefault();
}
}
44 changes: 41 additions & 3 deletions tests/Doki.Extensions.Tests/DocumentationRootExtensionTests.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Text.Json;
using System.Xml.XPath;
using Doki.TestAssembly.InheritanceChain;
using Doki.Tests.Common;
Expand Down Expand Up @@ -28,11 +29,48 @@ public async Task Test_TryGetParent_ParentPropertyIsNotNull()

var namespaceDocumentation = assemblyDocumentation.Namespaces.Single();

var simpleClassDocumentation = namespaceDocumentation.Types.First();
var typeDocumentation = namespaceDocumentation.Types.First();

Assert.NotNull(simpleClassDocumentation.Parent);
Assert.NotNull(typeDocumentation.Parent);

var parent = testOutput.Root.TryGetParent(simpleClassDocumentation);
var parent = testOutput.Root.TryGetParent<NamespaceDocumentation>(typeDocumentation);

Assert.NotNull(parent);
Assert.Equal(namespaceDocumentation, parent);
}

[Fact]
public async Task Test_TryGetParent_ParentPropertyIsNull()
{
var testOutput = new DocumentationRootCapture();

var documentationGenerator = new DocumentationGenerator();

var emptyDocumentation = new XPathDocument(new StringReader("""<?xml version="1.0"?><doc></doc>"""));

documentationGenerator.AddOutput(testOutput);

documentationGenerator.AddAssembly(typeof(SimpleClass).Assembly, emptyDocumentation);

await documentationGenerator.GenerateAsync(NullLogger.Instance);

Assert.NotNull(testOutput.Root);

var json = JsonSerializer.Serialize(testOutput.Root);

var deserialized = JsonSerializer.Deserialize<DocumentationRoot>(json);

Assert.NotNull(deserialized);

var assemblyDocumentation = deserialized.Assemblies.Single();

var namespaceDocumentation = assemblyDocumentation.Namespaces.Single();

var typeDocumentation = namespaceDocumentation.Types.First();

Assert.Null(typeDocumentation.Parent);

var parent = deserialized.TryGetParent<NamespaceDocumentation>(typeDocumentation);

Assert.NotNull(parent);
Assert.Equal(namespaceDocumentation, parent);
Expand Down

0 comments on commit 7a1aac9

Please sign in to comment.