energy164 / livingdocumentation Goto Github PK
View Code? Open in Web Editor NEWGenerate documentation based on your dotnet source code!
License: MIT License
Generate documentation based on your dotnet source code!
License: MIT License
When using the AnalyzerManager with a solution file path, the method has the ability to apply a ProjectFilter by using AnalyzerManagerOptions.
Using the optional parameter will allow for example for an exclusion of certain projects before they are added to the Workspace.
Example:
var managerOptions = new AnalyzerManagerOptions
{
ProjectFilter = x => !x.AbsolutePath.Contains("Tests")
};
var solutionManager = new AnalyzerManager(solutionFilePath, managerOptions);
return BadRequest();
results in
ReturnDescription { Expression = "BadRequest()" }
InvocationDescription { Name = "BadRequest" }
This should be the other way around.
This guide does not include all the available arguments:
https://github.com/eNeRGy164/LivingDocumentation/blob/main/docs/guide.md
Meanwhile there seems to have been a PR to exclude certain projects from the analysis.
The option to exclude is displayed in the Options class:
https://github.com/eNeRGy164/LivingDocumentation/blob/main/src/LivingDocumentation.Analyzer/Options.cs
The documentation should be updated to specify that
LivingDocumentation.Descriptions, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null' is not compatible with 'ConsoleApp1.Statement, ConsoleApp1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Path '[0].Constructors[0].Statements[0].$type', line 1, position 524.'
analysis.txt
<para>
tags should generate a newline in the generated documentation.
The generated output file does not always result in the same json file. It seems certain type descriptions are missing.
In case something is wrong it is better to let it fail rather than continuing with incomplete data.
analysis.txt
How can I access the items in the Controller Statements? These items generally are the same as the constructor parameters. I sometimes add statements that are not constructor parameters. These are LivingDocumentation.InvocationDescription type. The BowlController is an example.
Thank you for LivingDocument is a huge asset. It solves my lack of documentation problem that a lot of developers experience. I am incorporating it in all my projects. I have to figure out how to document Razor pages, but that's a later task.
Bill
I am attempting to work Living Documentation
into my Nuke.build
CI pipeline, but I'm getting stuck pretty quickly. I am able to generate the analysis file, but the deserialization of it fails.
LivingDocumentation.Statements
is identified as a transitive dependency by defaultnet7.0
all the way down <ItemGroup>
<PackageReference Include="LivingDocumentation.Json" Version="0.4.0" />
<PackageReference Include="LivingDocumentation.RenderExtensions" Version="0.4.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<PackageDownload Include="LivingDocumentation.Analyzer" Version="[0.4.0]" />
</ItemGroup>
[NuGetPackage(
packageId: "LivingDocumentation.Analyzer",
packageExecutable: "LivingDocumentation.Analyzer.dll",
Framework = "net7.0")]
readonly Tool Documentation;
Target Document => _ => _
.Executes(() =>
{
Documentation($"--solution {Solution.Path} --output {Paths.Artifacts.LivingDocumentation}");
string fileContent = File.ReadAllText(Paths.Artifacts.LivingDocumentation);
var types = JsonConvert.DeserializeObject<List<TypeDescription>>(fileContent, JsonDefaults.DeserializerSettings());
});
07:43:38 [INF] > /usr/bin/dotnet /home/user/.nuget/packages/livingdocumentation.analyzer/0.4.0/tools/net7.0/any/LivingDocumentation.Analyzer.dll --solution /home/user/dev/work/project/src/api/Bespoke.sln --output /home/user/dev/work/project/.artifacts/analysis.json
07:43:43 [DBG] Living Documentation Analysis output generated in 5313ms at /home/user/dev/work/project/.artifacts/analysis.json
07:43:43 [ERR] Target Document has thrown an exception
Newtonsoft.Json.JsonSerializationException: Error resolving type specified in JSON 'LivingDocumentation.If, LivingDocumentation.Statements'. Path '[1].Methods[0].Statements[4].$type', line 1, position 4124.
---> Newtonsoft.Json.JsonSerializationException: Could not load assembly 'LivingDocumentation.Statements'.
at Newtonsoft.Json.Serialization.DefaultSerializationBinder.GetTypeFromTypeNameKey(StructMultiKey`2 typeNameKey)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Newtonsoft.Json.Utilities.ThreadSafeStore`2.Get(TKey key)
...
Any ideas what I'm doing wrong?
Support a Visitor pattern to make traversing data in the tree easier en support more ways to render documentation
Add support for ReturnStatement and ArrowExpressionClause
CasePatternSwitchLabelSyntax Pattern is currently ignored when there is a when clause
Unhandled Exception: System.AggregateException: One or more errors occurred. (One or more errors occurred. (Could not find build environment)) (One or more errors occurred. (Could not find build environment)) (One or more errors occurred. (Could not find build environment)) (Could not find build environment) (Could not find build environment) (Could not find build environment) ---> System.InvalidOperationException: Could not find build environment
at Buildalyzer.Environment.EnvironmentFactory.GetBuildEnvironment(String targetFramework, EnvironmentOptions options)
at Buildalyzer.ProjectAnalyzer.Build(String targetFramework)
at Buildalyzer.Workspaces.AnalyzerManagerExtensions.<>c.b__0_0(ProjectAnalyzer p)
at System.Linq.Parallel.SelectQueryOperator2.SelectQueryOperatorResults.GetElement(Int32 index) at System.Linq.Parallel.QueryResults
1.get_Item(Int32 index)
at System.Linq.Parallel.PartitionedDataSource1.ListContiguousIndexRangeEnumerator.MoveNext(T& currentElement, Int32& currentKey) at System.Linq.Parallel.WhereQueryOperator
1.WhereQueryOperatorEnumerator1.MoveNext(TInputOutput& currentElement, TKey& currentKey) at System.Linq.Parallel.StopAndGoSpoolingTask
2.SpoolingWork()
at System.Linq.Parallel.SpoolingTaskBase.Work()
at System.Linq.Parallel.QueryTask.BaseWork(Object unused)
at System.Linq.Parallel.QueryTask.<>c.<.cctor>b__10_0(Object o)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot)
--- End of inner exception stack trace ---
at System.Linq.Parallel.QueryTaskGroupState.QueryEnd(Boolean userInitiatedDispose)
at System.Linq.Parallel.SpoolingTask.SpoolStopAndGo[TInputOutput,TIgnoreKey](QueryTaskGroupState groupState, PartitionedStream2 partitions, SynchronousChannel
1[] channels, TaskScheduler taskScheduler)
at System.Linq.Parallel.MergeExecutor1.Execute() at System.Linq.Parallel.MergeExecutor
1.Execute[TKey](PartitionedStream2 partitions, Boolean ignoreOutput, ParallelMergeOptions options, TaskScheduler taskScheduler, Boolean isOrdered, CancellationState cancellationState, Int32 queryId) at System.Linq.Parallel.PartitionedStreamMerger
1.Receive[TKey](PartitionedStream2 partitionedStream) at System.Linq.Parallel.WhereQueryOperator
1.WrapPartitionedStream[TKey](PartitionedStream2 inputStream, IPartitionedStreamRecipient
1 recipient, Boolean preferStriping, QuerySettings settings)
at System.Linq.Parallel.UnaryQueryOperator2.UnaryQueryOperatorResults.ChildResultsRecipient.Receive[TKey](PartitionedStream
2 inputStream)
at System.Linq.Parallel.UnaryQueryOperator2.UnaryQueryOperatorResults.GivePartitionedStream(IPartitionedStreamRecipient
1 recipient)
at System.Linq.Parallel.UnaryQueryOperator2.UnaryQueryOperatorResults.GivePartitionedStream(IPartitionedStreamRecipient
1 recipient)
at System.Linq.Parallel.QueryOperator1.GetOpenedEnumerator(Nullable
1 mergeOptions, Boolean suppressOrder, Boolean forEffect, QuerySettings querySettings)
at System.Linq.Parallel.QueryOpeningEnumerator1.OpenQuery() at System.Linq.Parallel.QueryOpeningEnumerator
1.MoveNext()
at System.Linq.ParallelEnumerable.ToList[TSource](ParallelQuery`1 source)
at Buildalyzer.Workspaces.AnalyzerManagerExtensions.GetWorkspace(AnalyzerManager manager)
When analyzing https://github.com/EdwinVW/pitstop which switched to NET5, containing types might be null
.
Need to be investigated.
It seems partial classes are nog handled correctly during analysis.
I made a specialized collection for mutable large structs. To mutate a struct member by this indexer, it returns a reference. While analyzer processing this file, it thrown an exception and stopped generation.
Here is the repro code snippet:
public struct ListStruct<T> : IEnumerable<T> where T : unmanaged
{
internal int CountInternal;
private T[] _storage;
// ...
public readonly ref T this[int index]
{
[method: MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref _storage[index];
}
// ...
And here is the stack trace:
System.Collections.Generic.KeyNotFoundException: Could not resolve a display name for ref T
at LivingDocumentation.SemanticModelExtensions.GetTypeDisplayString(SemanticModel semanticModel, ExpressionSyntax expression) in /_/src/LivingDocumentation.Analyzer/Extensions/SemanticModelExtensions.cs:line 24
at LivingDocumentation.SourceAnalyzer.VisitPropertyDeclaration(PropertyDeclarationSyntax node) in /_/src/LivingDocumentation.Analyzer/Analyzers/SourceAnalyzer.cs:line 158
at Microsoft.CodeAnalysis.CSharp.Syntax.PropertyDeclarationSyntax.Accept(CSharpSyntaxVisitor visitor)
...
Hope these information will help.
How to start simple with a simple class diagram or sequence diagram
Have a better description of the project in the README, for example the Why.
Currently it is only possible to navigate from the top down, but not back up.
During/after deserialization, objects like MethodDescription
, Statement
, etc. should have a Parent
property to navigate up the tree.
This would reduce complexity when querying the tree.
First, thank you for this great tool!
When I run your tool on the eshop on containers as in your description, I get the following error:
D:\C#\Test\LivingDoc\eShopOnContainers>livingdoc-analyze --solution src/eShopOnContainers-ServicesAndWebApps.sln --output analysis.json
Unhandled exception. System.ArgumentNullException: Value cannot be null. (Parameter 'containingType')
at LivingDocumentation.InvocationDescription..ctor(String containingType, String name) in //src/LivingDocumentation.Descriptions/InvocationDescription.cs:line 14
at LivingDocumentation.InvocationsAnalyzer.VisitInvocationExpression(InvocationExpressionSyntax node) in //src/LivingDocumentation.Analyzer/Analyzers/InvocationsAnalyzer.cs:line 95
at Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax.Accept(CSharpSyntaxVisitor visitor)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.Visit(SyntaxNode node)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.DefaultVisit(SyntaxNode node)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitEqualsValueClause(EqualsValueClauseSyntax node)
at Microsoft.CodeAnalysis.CSharp.Syntax.EqualsValueClauseSyntax.Accept(CSharpSyntaxVisitor visitor)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.Visit(SyntaxNode node)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.DefaultVisit(SyntaxNode node)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitVariableDeclarator(VariableDeclaratorSyntax node)
at Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclaratorSyntax.Accept(CSharpSyntaxVisitor visitor)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.Visit(SyntaxNode node)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.DefaultVisit(SyntaxNode node)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitVariableDeclaration(VariableDeclarationSyntax node)
at Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax.Accept(CSharpSyntaxVisitor visitor)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.Visit(SyntaxNode node)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.DefaultVisit(SyntaxNode node)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node)
at Microsoft.CodeAnalysis.CSharp.Syntax.LocalDeclarationStatementSyntax.Accept(CSharpSyntaxVisitor visitor)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.Visit(SyntaxNode node)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.DefaultVisit(SyntaxNode node)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitBlock(BlockSyntax node)
at Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax.Accept(CSharpSyntaxVisitor visitor)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.Visit(SyntaxNode node)
at LivingDocumentation.BranchingAnalyzer.VisitIfStatement(IfStatementSyntax node) in //src/LivingDocumentation.Analyzer/Analyzers/BranchingAnalyzer.cs:line 25
at Microsoft.CodeAnalysis.CSharp.Syntax.IfStatementSyntax.Accept(CSharpSyntaxVisitor visitor)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.Visit(SyntaxNode node)
at LivingDocumentation.InvocationsAnalyzer.VisitIfStatement(IfStatementSyntax node) in //src/LivingDocumentation.Analyzer/Analyzers/InvocationsAnalyzer.cs:line 51
at Microsoft.CodeAnalysis.CSharp.Syntax.IfStatementSyntax.Accept(CSharpSyntaxVisitor visitor)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.Visit(SyntaxNode node)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.DefaultVisit(SyntaxNode node)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitBlock(BlockSyntax node)
at Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax.Accept(CSharpSyntaxVisitor visitor)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.Visit(SyntaxNode node)
at LivingDocumentation.SourceAnalyzer.ExtractBaseMethodDeclaration(BaseMethodDeclarationSyntax node, IHaveAMethodBody method) in //src/LivingDocumentation.Analyzer/Analyzers/SourceAnalyzer.cs:line 326
at LivingDocumentation.SourceAnalyzer.VisitMethodDeclaration(MethodDeclarationSyntax node) in //src/LivingDocumentation.Analyzer/Analyzers/SourceAnalyzer.cs:line 203
at Microsoft.CodeAnalysis.CSharp.Syntax.MethodDeclarationSyntax.Accept(CSharpSyntaxVisitor visitor)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.Visit(SyntaxNode node)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.DefaultVisit(SyntaxNode node)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitClassDeclaration(ClassDeclarationSyntax node)
at LivingDocumentation.SourceAnalyzer.VisitClassDeclaration(ClassDeclarationSyntax node) in //src/LivingDocumentation.Analyzer/Analyzers/SourceAnalyzer.cs:line 22
at Microsoft.CodeAnalysis.CSharp.Syntax.ClassDeclarationSyntax.Accept(CSharpSyntaxVisitor visitor)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.Visit(SyntaxNode node)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.DefaultVisit(SyntaxNode node)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFileScopedNamespaceDeclaration(FileScopedNamespaceDeclarationSyntax node)
at Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.Accept(CSharpSyntaxVisitor visitor)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.Visit(SyntaxNode node)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.DefaultVisit(SyntaxNode node)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitCompilationUnit(CompilationUnitSyntax node)
at Microsoft.CodeAnalysis.CSharp.Syntax.CompilationUnitSyntax.Accept(CSharpSyntaxVisitor visitor)
at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker.Visit(SyntaxNode node)
at LivingDocumentation.Program.AnalyzeProjectAsyc(List1 types, Project project) in /_/src/LivingDocumentation.Analyzer/Program.cs:line 113 at LivingDocumentation.Program.AnalyzeSolutionFileAsync(List
1 types, String solutionFile) in //src/LivingDocumentation.Analyzer/Program.cs:line 67
at LivingDocumentation.Program.RunApplicationAsync(Options options) in //src/LivingDocumentation.Analyzer/Program.cs:line 33
at LivingDocumentation.Program.Main(String[] args) in //src/LivingDocumentation.Analyzer/Program.cs:line 18
at LivingDocumentation.Program.
I Guess that this needs to be more robust. Rather skip something than not doing anything
Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
at LivingDocumentation.Program.<>c.b__8_3(IPackageReference pr) in /home/vsts/work/1/s/src/LivingDocumentation.Analyzer/Program.cs:line 63
at System.Linq.Enumerable.Any[TSource](IEnumerable1 source, Func
2 predicate)
at LivingDocumentation.Program.<>c__DisplayClass8_0.b__1(Project p) in /home/vsts/work/1/s/src/LivingDocumentation.Analyzer/Program.cs:line 63
at System.Linq.Enumerable.WhereEnumerableIterator1.MoveNext() at LivingDocumentation.Program.AnalyzeSolutionAsync(IList
1 types, String solutionFile) in /home/vsts/work/1/s/src/LivingDocumentation.Analyzer/Program.cs:line 65
at LivingDocumentation.Program.RunApplicationAsync(Options options) in /home/vsts/work/1/s/src/LivingDocumentation.Analyzer/Program.cs:line 38
at LivingDocumentation.Program.Main(String[] args) in /home/vsts/work/1/s/src/LivingDocumentation.Analyzer/Program.cs:line 25
at LivingDocumentation.Program.
Consider the following code snippet:
if (string.IsNullOrWhiteSpace(filename))
throw new ArgumentException(@"Filename cannot be null or whitespace.", nameof(filename));
Within C#, nameof is a contextual keyword. This means there is no way to distinguish the nameof keyword from a call to a method that happens to be named nameof.
When the previous code gets visited, the nameof(filename) node gets processed by the VisitInvocationExpression as an InvocationExpressionSyntax.
https://github.com/eNeRGy164/LivingDocumentation/blob/main/src/LivingDocumentation.Analyzer/Analyzers/InvocationsAnalyzer.cs
The GetExpressionWithSymbol method returns null (this.semanticModel.GetSymbolInfo(expression).Symbol is null).
When running in verbose, the output will display all the occurences of nameof():
WARN: Could not resolve type of invocation of the following block:
The question is: should these particular cases be ignored altogether, or should they be handled?
Note: a similar situation is encounted with dynamic types:
public void MyMethod(dynamic dynamicPayload)
{
string realPayload = JsonConvert.SerializeObject(dynamicPayload);
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.