statiqdev / Statiq.Docs

A static documentation site generator.
https://statiq.dev/docs
Other
53 stars 8 forks source link

Support for type-safe enum pattern. #59

Open Foxtrek64 opened 1 year ago

Foxtrek64 commented 1 year ago

I am building docs for my Electronic Data Interchange library. One of the files in this library uses the type-safe enum pattern in order to define Currency Codes.

When the API docs are rendered for this class, the static readonly members are listed, however their values are not readily available even after clicking on them. Where is the value of this property stored and how can it be recovered for viewing?

daveaglick commented 1 year ago

Interesting - all the data is coming from Roslyn, and Statiq Docs essentially converts Roslyn symbols representations to Statiq Documents so we can more easily work with them. My guess is that the Docable theme doesn't know where to look for the value of these static readonly fields. Probably won't be too hard to add that - can you paste some code here showing exactly the pattern that you're using (I can probably guess, but want to make sure I'm replicating the problem exactly).

Foxtrek64 commented 1 year ago

I'm using a slightly modified version of Docable. Layout is mostly the same, but I've changed some properties here and there.

section/_Properties.cshtml

@{
    IReadOnlyList<IDocument> properties = Document.GetDocumentList(CodeAnalysisKeys.Members)
        ?.Where(x => x.GetBool(CodeAnalysisKeys.IsResult) && x.GetString(CodeAnalysisKeys.Kind) == "Property")
        .OrderBy(x => x.GetString(CodeAnalysisKeys.DisplayName))
        .ToList()
        ?? new List<IDocument>();
    if (properties?.Count > 0)
    {
        List<(string, string)> headings = (List<(string, string)>?)ViewData[Keys.Headings] ?? new List<(string, string)>();
        headings.Add(("properties", "Properties"));
        ViewData[Keys.Headings] = headings;
        <h2 id="properties">Properties</h2>
        <div class="table-responsive">
            <table class="table table-api table-striped table-hover three-cols">
                <thead>
                    <tr>
                        <th>Name</th>
                        <th>Property Type</th>
                        <th>Summary</th>
                    </tr>
                </thead>
                <tbody>
                    @foreach (IDocument property in properties)
                    {
                        <tr>
                            <td>@Context.GetTypeLink(property, false)</td>
                            <td>@Context.GetTypeLink(property.GetDocument(CodeAnalysisKeys.Type))</td>
                            <td>
                                <div>@Html.Raw(property.GetString(CodeAnalysisKeys.Summary))</div>
                                @{
                                    IDocument containingType = property.GetDocument(CodeAnalysisKeys.ContainingType);
                                    if (!Document.IdEquals(containingType))
                                    {
                                        <div><small><em>Inherited from @Context.GetTypeLink(containingType)</em></small></div>
                                    }
                                    if (property.GetBool(CodeAnalysisKeys.IsStatic))
                                    {
                                        <div><small><em>static</em></small></div>
                                    }
                                }
                            </td>
                        </tr>
                    }
                </tbody>
            </table>
        </div>
    }
}

section/_ConstantValue.cshtml

@using Microsoft.AspNetCore.Html;

@if (Document.GetBool(CodeAnalysisKeys.ConstantValue))
{
    List<(string, string)> headings = (List<(string, string)>?)ViewData[Keys.Headings] ?? new List<(string, string)>();
    headings.Add(("constant-value", "Constant Value"));
    ViewData[Keys.Headings] = headings;
    var constantValue = Document.Get(CodeAnalysisKeys.ConstantValue);

    <h2 id="constant-value">Constant Value</h2>
    <div class="table-responsive">
        <table class="table table-api table-striped table-hover two-cols">
            <thead>
                <tr>
                    <th>Value</th>
                    <th>Type</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>@(new HtmlString(constantValue?.ToString() ?? "null"))</td>
                    <td>@(new HtmlString(constantValue?.GetType().Name ?? string.Empty))</td>
                </tr>
            </tbody>
        </table>
    </div>
}

Edit: Here's a small type-safe enum example: Essentially, it aims to replicate Enum CustomerCode : T where T is anything, but it lacks some obvious features of enums such as being able to be used in a switch statement (values aren't constant), no flag support unless implemented manually, and so forth. Generally best used for when you need an explicit enumeration, such as where you'd use an enum, but where using an enum is not possible due to type restraints. These will be going away most likely when we get Discriminated Unions, but this is some time away.


public sealed class CustomerCode
{
    public string Code { get; }

    private CustomerCode(string code)
    {
        Code = code
    }

    public static readonly CustomerCode Contoso = new("Con01");
    public static readonly CustomerCode Microsoft = new ("Msft01");
}