Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
54 changes: 39 additions & 15 deletions src/DotnetDocument.Tools/Handlers/ApplyDocumentHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class ApplyDocumentHandler : IApplyDocumentHandler
/// <summary>
/// The service resolver
/// </summary>
private readonly IServiceResolver<IDocumentationStrategy> _serviceResolver;
private readonly IServiceResolver<IDocumentationStrategy> _strategyResolver;

/// <summary>
/// The walker
Expand All @@ -49,7 +49,7 @@ public class ApplyDocumentHandler : IApplyDocumentHandler
public ApplyDocumentHandler(ILogger<ApplyDocumentHandler> logger,
IServiceResolver<IDocumentationStrategy> serviceResolver,
DocumentationSyntaxWalker walker, IOptions<DocumentationOptions> appSettings) =>
(_logger, _serviceResolver, _walker, _documentationSettings) =
(_logger, _strategyResolver, _walker, _documentationSettings) =
(logger, serviceResolver, walker, appSettings.Value);

/// <summary>
Expand All @@ -73,11 +73,13 @@ public Result Apply(string? path, bool isDryRun)
var memberDocStatusList = GetFilesDocumentationStatus(files);

// Get the list of undocumented members
var undocumentedMembers = memberDocStatusList.Where(m => m.IsDocumented is not true).ToList();
var undocumentedMembers = memberDocStatusList.Where(m => m.NeedsDocumentation).ToList();

foreach (var member in undocumentedMembers)
_logger.LogInformation(" {File} (ln {Line}): {MemberType} '{MemberName}' has no document",
{
_logger.LogInformation(" {File} (ln {Line}): {MemberType} '{MemberName}' has no documentation",
member.FilePath, member.StartLine, member.Kind.ToString().Humanize(), member.Identifier);
}

// If is dry run
if (isDryRun)
Expand All @@ -87,7 +89,7 @@ public Result Apply(string? path, bool isDryRun)

// Don't go ahead with saving.
// If there are members without doc return `undocumented members`
return memberDocStatusList.Any(m => m.IsDocumented is not true)
return memberDocStatusList.Any(m => m.NeedsDocumentation)
? Result.UndocumentedMembers
: Result.Success;
}
Expand All @@ -110,10 +112,19 @@ public Result Apply(string? path, bool isDryRun)

// Replace the
var changedSyntaxTree = root.ReplaceNodes(_walker.NodesWithoutXmlDoc,
(node, syntaxNode) => _serviceResolver
.Resolve(syntaxNode.Kind().ToString())
?
.Apply(syntaxNode) ?? syntaxNode);
(originalNode, replacedNode) =>
{
var documentationAttempt = _strategyResolver
.Resolve(replacedNode.Kind().ToString())
?.Apply(replacedNode);

if (documentationAttempt is null || documentationAttempt.Value.IsChanged is false)
{
return replacedNode;
}

return documentationAttempt.Value.NodeWithDocs;
});

// TODO: Don't write if no changes

Expand Down Expand Up @@ -158,19 +169,32 @@ private IEnumerable<MemberDocumentationStatus> GetFileDocumentationStatus(string
_walker.Visit(root);

foreach (var node in _walker.NodesWithXmlDoc)
{
yield return new MemberDocumentationStatus(filePath, SyntaxUtils.FindMemberIdentifier(node),
node.Kind(), true, null, node,
node.Kind(), needsDocumentation: false, nodeWithoutDocument: null, documentedNode: node,
node.GetLocation().GetLineSpan().StartLinePosition.ToString());
}

foreach (var node in _walker.NodesWithoutXmlDoc)
{
var nodeWithDoc = _serviceResolver
.Resolve(node.Kind().ToString())
?
.Apply(node);
var documentationStrategy = _strategyResolver
.Resolve(node.Kind().ToString());

// If not documentation strategy found for this node type then skip it
if (documentationStrategy is null)
{
_logger.LogWarning("Documentation strategy is null");
yield break;
}

var (needsDocumentation, nodeWithDocs) = documentationStrategy.Apply(node);

var nodeWithoutXmlDocs = needsDocumentation ? node : null;
var nodeWithXmlDocs = needsDocumentation ? nodeWithDocs : node;

yield return new MemberDocumentationStatus(filePath, SyntaxUtils.FindMemberIdentifier(node),
node.Kind(), false, node, nodeWithDoc,
node.Kind(), needsDocumentation: needsDocumentation, nodeWithoutDocument: nodeWithoutXmlDocs,
documentedNode: nodeWithXmlDocs,
node.GetLocation().GetLineSpan().StartLinePosition.ToString());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ public class MemberDocumentationStatus
/// <param name="filePath">The file path</param>
/// <param name="identifier">The identifier</param>
/// <param name="kind">The kind</param>
/// <param name="isDocumented">The is documented</param>
/// <param name="needsDocumentation">The is documented</param>
/// <param name="nodeWithoutDocument">The node without document</param>
/// <param name="documentedNode">The documented node</param>
/// <param name="startLine">The start line</param>
public MemberDocumentationStatus(string filePath, string identifier, SyntaxKind kind, bool isDocumented,
public MemberDocumentationStatus(string filePath, string identifier, SyntaxKind kind, bool needsDocumentation,
SyntaxNode? nodeWithoutDocument, SyntaxNode? documentedNode, string startLine)
{
FilePath = filePath;
Identifier = identifier;
Kind = kind;
IsDocumented = isDocumented;
NeedsDocumentation = needsDocumentation;
NodeWithoutDocument = nodeWithoutDocument;
DocumentedNode = documentedNode;
StartLine = startLine;
Expand All @@ -48,7 +48,7 @@ public MemberDocumentationStatus(string filePath, string identifier, SyntaxKind
/// <summary>
/// Gets or inits the value of the is documented
/// </summary>
public bool IsDocumented { get; init; }
public bool NeedsDocumentation { get; init; }

/// <summary>
/// Gets the value of the node without document
Expand Down
33 changes: 19 additions & 14 deletions src/DotnetDocument/Configuration/DocumentationOptions.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using Microsoft.CodeAnalysis.CSharp;

Expand All @@ -18,6 +19,17 @@ public abstract class MemberDocumentationOptionsBase
/// </summary>
public bool Required { get; init; } = true;

/// <summary>
/// Gets or sets the value of the apply on modifiers
/// </summary>
public List<string> ApplyOnModifiers { get; set; } = new()
{
"public",
//"private",
//"internal",
//"protected"
};

/// <summary>
/// Gets the syntax kind
/// </summary>
Expand Down Expand Up @@ -484,28 +496,22 @@ public class DocumentationOptions
public Dictionary<string, string> Verbs { get; init; } = new()
{
{
"to",
"returns"
"to", "returns"
},
{
"from",
"creates"
"from", "creates"
},
{
"as",
"converts"
"as", "converts"
},
{
"with",
"adds"
"with", "adds"
},
{
"setup",
"setup"
"setup", "setup"
},
{
"main",
"main"
"main", "main"
}
};

Expand All @@ -515,8 +521,7 @@ public class DocumentationOptions
public Dictionary<string, string> Aliases { get; init; } = new()
{
{
"sut",
"system under test"
"sut", "system under test"
}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
Expand All @@ -9,6 +10,7 @@ namespace DotnetDocument.Strategies.Abstractions
/// The attribute service resolver class
/// </summary>
/// <seealso cref="IServiceResolver{TService}" />
[SuppressMessage("Performance", "CA1848:Use the LoggerMessage delegates")]
public class AttributeServiceResolver<TService> : IServiceResolver<TService>
{
/// <summary>
Expand Down Expand Up @@ -45,11 +47,15 @@ public AttributeServiceResolver(IServiceProvider provider) =>
.Any(a => a.Key == key));

if (service is null)
{
logger.LogWarning("No {ServiceType} implementation resolved matching {KeyType} key: '{Key}'",
typeof(TService).Name, key.GetType().Name, key);
}
else
{
logger.LogTrace("Resolved implementation of {ServiceType} with key '{Key}': {ImplementationType}",
typeof(TService).Name, key, service.GetType().Name);
}

return service;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,16 @@ public abstract class DocumentationStrategyBase<T> : IDocumentationStrategy wher
/// Applies the node
/// </summary>
/// <param name="node">The node</param>
/// <returns>The syntax node</returns>
public SyntaxNode Apply(SyntaxNode node) => Apply(node as T ?? throw new InvalidOperationException());
/// <returns>The bool is changed syntax node node with docs</returns>
public (bool IsChanged, SyntaxNode NodeWithDocs) Apply(SyntaxNode node) =>
Apply(node as T ?? throw new InvalidOperationException());

/// <summary>
/// Applies the node
/// </summary>
/// <param name="node">The node</param>
/// <returns>The</returns>
public abstract T Apply(T node);
/// <returns>The bool is changed node with docs</returns>
public abstract (bool IsChanged, T NodeWithDocs) Apply(T node);

/// <summary>
/// Gets the documentation builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ public interface IDocumentationStrategy
/// <returns>An enumerable of syntax kind</returns>
IEnumerable<SyntaxKind> GetSupportedKinds();

/// <summary>
/// Applies the node
/// </summary>
/// <param name="node">The node</param>
/// <returns>The syntax node</returns>
SyntaxNode Apply(SyntaxNode node);
(bool IsChanged, SyntaxNode NodeWithDocs) Apply(SyntaxNode node);
}
}
9 changes: 6 additions & 3 deletions src/DotnetDocument/Strategies/ClassDocumentationStrategy.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DotnetDocument.Configuration;
Expand Down Expand Up @@ -55,9 +56,11 @@ public override IEnumerable<SyntaxKind> GetSupportedKinds() => new[]
/// Applies the node
/// </summary>
/// <param name="node">The node</param>
/// <returns>The class declaration syntax</returns>
public override ClassDeclarationSyntax Apply(ClassDeclarationSyntax node)
/// <returns>The bool is changed class declaration syntax node with docs</returns>
public override (bool IsChanged, ClassDeclarationSyntax NodeWithDocs) Apply(ClassDeclarationSyntax node)
{
ArgumentNullException.ThrowIfNull(node);

// Retrieve class name
var className = node.Identifier.Text;

Expand All @@ -82,7 +85,7 @@ public override ClassDeclarationSyntax Apply(ClassDeclarationSyntax node)
builder.WithSeeAlso(baseTypes);
}

return builder.Build();
return (true, builder.Build());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DotnetDocument.Configuration;
Expand Down Expand Up @@ -55,16 +56,20 @@ public override IEnumerable<SyntaxKind> GetSupportedKinds() => new[]
/// Applies the node
/// </summary>
/// <param name="node">The node</param>
/// <returns>The constructor declaration syntax</returns>
public override ConstructorDeclarationSyntax Apply(ConstructorDeclarationSyntax node)
/// <returns>The bool is changed constructor declaration syntax node with docs</returns>
public override (bool IsChanged, ConstructorDeclarationSyntax NodeWithDocs) Apply(
ConstructorDeclarationSyntax node)
{
ArgumentNullException.ThrowIfNull(node);

// Retrieve constructor name
var ctorName = SyntaxUtils.ExtractClassName(node);

// Declare the summary by using the template from configuration
var summary = new List<string>
{
_options.Summary.Template.Replace(TemplateKeys.Name, $"<<{ctorName}>>")
_options.Summary.Template.Replace(TemplateKeys.Name, $"<<{ctorName}>>",
StringComparison.InvariantCulture)
};

var exceptions = new List<(string, string)>();
Expand Down Expand Up @@ -97,12 +102,14 @@ public override ConstructorDeclarationSyntax Apply(ConstructorDeclarationSyntax
.Select(p => (p, _formatter
.FormatName(_options.Parameters.Template, (TemplateKeys.Name, p))));

return GetDocumentationBuilder()
var nodeWithDocs = GetDocumentationBuilder()
.For(node)
.WithSummary(summary.ToArray())
.WithParams(@params)
.WithExceptions(exceptions.ToArray())
.Build();

return (true, nodeWithDocs);
}
}
}
18 changes: 16 additions & 2 deletions src/DotnetDocument/Strategies/DefaultDocumentationStrategy.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DotnetDocument.Configuration;
using DotnetDocument.Format;
using DotnetDocument.Strategies.Abstractions;
Expand Down Expand Up @@ -65,8 +67,18 @@ public override IEnumerable<SyntaxKind> GetSupportedKinds() => new[]
/// </summary>
/// <param name="node">The node</param>
/// <returns>The member declaration syntax</returns>
public override MemberDeclarationSyntax Apply(MemberDeclarationSyntax node)
public override (bool IsChanged, MemberDeclarationSyntax NodeWithDocs) Apply(MemberDeclarationSyntax node)
{
ArgumentNullException.ThrowIfNull(node);

var memberModifiers = node.Modifiers.Select(m => m.Text);
var allowedModifiers = _options.ApplyOnModifiers;

if (memberModifiers.Any(m => allowedModifiers.Contains(m)) is false)
{
return (false, node);
}

// Retrieve member name
var name = SyntaxUtils.FindMemberIdentifier(node);

Expand All @@ -77,10 +89,12 @@ public override MemberDeclarationSyntax Apply(MemberDeclarationSyntax node)
(TemplateKeys.Name, name))
};

return GetDocumentationBuilder()
var nodeWithDocs = GetDocumentationBuilder()
.For(node)
.WithSummary(summary.ToArray())
.Build();

return (true, nodeWithDocs);
}
}
}
Loading