diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 782d4c06f..981d56ebf 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -10,7 +10,7 @@ "rollForward": false }, "fornax": { - "version": "0.13.1", + "version": "0.16.0-beta002", "commands": [ "fornax" ], diff --git a/.github/workflows/build+test+deploy.yml b/.github/workflows/build+test+deploy.yml index 8471e2b80..50979a733 100644 --- a/.github/workflows/build+test+deploy.yml +++ b/.github/workflows/build+test+deploy.yml @@ -107,12 +107,6 @@ jobs: with: dotnet-version: ${{ env.DOTNET_VERSION }} - # old .NET required by old fornax version - - name: Setup old .NET - uses: actions/setup-dotnet@v3 - with: - dotnet-version: 3.1.x - - name: Restore tools run: dotnet tool restore - name: Restore dependencies diff --git a/build.fsx b/build.fsx index 129fc2c09..93bbb92d9 100644 --- a/build.fsx +++ b/build.fsx @@ -84,6 +84,7 @@ let DoNothing = ignore let buildDir = "./build/" let nugetDir = "./out/" +let docsDir = "./docs/" let rootDir = __SOURCE_DIRECTORY__ |> DirectoryInfo System.Environment.CurrentDirectory <- rootDir.FullName @@ -153,7 +154,7 @@ Target.create "Test" (fun _ -> ) Target.create "Docs" (fun _ -> - exec "dotnet" @"fornax build" "docs" + exec "dotnet" "fornax build" docsDir ) // -------------------------------------------------------------------------------------- diff --git a/docs/_lib/Fornax.Core.dll b/docs/_lib/Fornax.Core.dll deleted file mode 100644 index b8754840a..000000000 Binary files a/docs/_lib/Fornax.Core.dll and /dev/null differ diff --git a/docs/config.fsx b/docs/config.fsx index 2e724c98f..51837efb4 100644 --- a/docs/config.fsx +++ b/docs/config.fsx @@ -1,4 +1,4 @@ -#r "_lib/Fornax.Core.dll" +#r "nuget: Fornax.Core, 0.16.0-beta002" open Config diff --git a/docs/config.fsx.lock b/docs/config.fsx.lock index db3f86c72..4d3cbd809 100644 --- a/docs/config.fsx.lock +++ b/docs/config.fsx.lock @@ -2,4 +2,5 @@ STORAGE: NONE RESTRICTION: == netstandard2.0 NUGET remote: https://api.nuget.org/v3/index.json - FSharp.Core (4.7.2) + FSharp.Compiler.Service (41.0.7) + FSharp.Core (6.0.7) diff --git a/docs/generators/apiref.fsx b/docs/generators/apiref.fsx index 559dbb13d..ca11ea06a 100644 --- a/docs/generators/apiref.fsx +++ b/docs/generators/apiref.fsx @@ -1,7 +1,6 @@ -#r "../_lib/Fornax.Core.dll" -#r "../../packages/docs/Markdig/lib/netstandard2.0/Markdig.dll" -#r "../../packages/docs/Newtonsoft.Json/lib/netstandard2.0/Newtonsoft.Json.dll" -#r "../../packages/docs/FSharp.Formatting/lib/netstandard2.0/FSharp.MetadataFormat.dll" +#r "nuget: Fornax.Core, 0.16.0-beta002" +#r "nuget: Markdig, 0.41.3" +#r "nuget: FSharp.Formatting, 20.0.1" #if !FORNAX #load "../loaders/apirefloader.fsx" @@ -10,7 +9,8 @@ #load "partials/layout.fsx" open System -open FSharp.MetadataFormat +open System.Text.Json +open FSharp.Formatting.ApiDocs open Html open Apirefloader open Markdig @@ -21,7 +21,7 @@ let markdownPipeline = .UseGridTables() .Build() -let getComment (c: Comment) = +let getComment (c: ApiDocComment) = let t = c.RawData |> List.map (fun n -> n.Value) @@ -29,7 +29,7 @@ let getComment (c: Comment) = Markdown.ToHtml(t, markdownPipeline) -let formatMember (m: Member) = +let formatMember (m: ApiDocMember) = let attributes = m.Attributes |> List.filter (fun a -> a.FullName <> "Microsoft.FSharp.Core.CustomOperationAttribute") @@ -62,7 +62,8 @@ let formatMember (m: Member) = br [] br [] b [] [!! "Signature: "] - !!m.Details.Signature + match m.Details with + | ApiDocMemberDetails(usageHtml, _, _, _, _, _, _, _) -> !!usageHtml.HtmlText br [] if not (attributes.IsEmpty) then b [] [!! "Attributes:"] @@ -72,103 +73,117 @@ let formatMember (m: Member) = td [] [!! (getComment m.Comment)] ] -let generateType ctx (page: ApiPageInfo) = +let generateType ctx (page: ApiPageInfo) = let t = page.Info let body = div [Class "api-page"] [ h2 [] [!! t.Name] b [] [!! "Namespace: "] - a [Href ($"%s{page.NamespaceUrlName}.html")] [!! page.NamespaceName] + a [Href ($"../%s{page.NamespaceUrlName}.html")] [!! page.NamespaceName] br [] - b [] [!! "Parent: "] - a [Href ($"%s{page.ParentUrlName}.html")] [!! page.ParentName] - span [] [!! (getComment t.Comment)] + if page.ParentName <> page.NamespaceName then + b [] [!! "Parent Module: "] + a [Href ($"../%s{page.ParentUrlName}.html")] [!! page.ParentName] + br [] + b [] [!! "Assembly: "] + !! t.Assembly.Name br [] if not (String.IsNullOrWhiteSpace t.Category) then - b [] [!! "Category:"] + b [] [!! "Category: "] !!t.Category br [] if not (t.Attributes.IsEmpty) then - b [] [!! "Attributes:"] + b [] [!! "Attributes: "] for a in t.Attributes do - br [] code [] [!! (a.Name)] - br [] + br [] + br [] table [] [ tr [] [ th [ Width "35%" ] [!!"Name"] th [ Width "65%"] [!!"Description"] ] - if not t.Constructors.IsEmpty then tr [] [ td [ColSpan 3. ] [ b [] [!! "Constructors"]]] + if not (t.Constructors : ApiDocMember list).IsEmpty then tr [] [ td [ColSpan 2. ] [ b [] [!! "Constructors"]]] yield! t.Constructors |> List.map formatMember - if not t.InstanceMembers.IsEmpty then tr [] [ td [ColSpan 3. ] [ b [] [!! "Instance Members"]]] + if not (t.InstanceMembers : ApiDocMember list).IsEmpty then tr [] [ td [ColSpan 2. ] [ b [] [!! "Instance Members"]]] yield! t.InstanceMembers |> List.map formatMember - if not t.RecordFields.IsEmpty then tr [] [ td [ColSpan 3. ] [ b [] [!! "Record Fields"]]] - yield! t.RecordFields |> List.map formatMember + // Record Fields from AllMembers + let recordFields = t.AllMembers |> List.filter (fun m -> m.Kind = ApiDocMemberKind.RecordField) + if not recordFields.IsEmpty then tr [] [ td [ColSpan 2. ] [ b [] [!! "Record Fields"]]] + yield! recordFields |> List.map formatMember - if not t.StaticMembers.IsEmpty then tr [] [ td [ColSpan 3. ] [ b [] [!! "Static Members"]]] + if not (t.StaticMembers : ApiDocMember list).IsEmpty then tr [] [ td [ColSpan 2. ] [ b [] [!! "Static Members"]]] yield! t.StaticMembers |> List.map formatMember - if not t.StaticParameters.IsEmpty then tr [] [ td [ColSpan 3. ] [ b [] [!! "Static Parameters"]]] - yield! t.StaticParameters |> List.map formatMember + // Static Parameters from AllMembers + let staticParams = t.AllMembers |> List.filter (fun m -> m.Kind = ApiDocMemberKind.StaticParameter) + if not staticParams.IsEmpty then tr [] [ td [ColSpan 2. ] [ b [] [!! "Static Parameters"]]] + yield! staticParams |> List.map formatMember - if not t.UnionCases.IsEmpty then tr [] [ td [ColSpan 3. ] [ b [] [!! "Union Cases"]]] - yield! t.UnionCases |> List.map formatMember + // Union Cases from AllMembers + let unionCases = t.AllMembers |> List.filter (fun m -> m.Kind = ApiDocMemberKind.UnionCase) + if not unionCases.IsEmpty then tr [] [ td [ColSpan 2. ] [ b [] [!! "Union Cases"]]] + yield! unionCases |> List.map formatMember ] ] - t.UrlName, Layout.layout ctx [body] t.Name + t.UrlBaseName, Layout.layout ctx [body] t.Name -let generateModule ctx (page: ApiPageInfo) = +let generateModule ctx (page: ApiPageInfo) = let m = page.Info let body = div [Class "api-page"] [ - h2 [] [!!m.Name] + h2 [] [!! m.Name] b [] [!! "Namespace: "] - a [Href ($"%s{page.NamespaceUrlName}.html")] [!! page.NamespaceName] - br [] - b [] [!! "Parent: "] - a [Href ($"%s{page.ParentUrlName}.html")] [!! page.ParentName] - span [] [!! (getComment m.Comment)] + a [Href ($"../%s{page.NamespaceUrlName}.html")] [!! page.NamespaceName] br [] + if page.ParentName <> page.NamespaceName then + b [] [!! "Parent Module: "] + a [Href ($"../%s{page.ParentUrlName}.html")] [!! page.ParentName] + br [] if not (String.IsNullOrWhiteSpace m.Category) then - b [] [!! "Category:"] + b [] [!! "Category: "] !!m.Category br [] + br [] + + // Split NestedEntities into types and modules + let nestedTypes = m.NestedEntities |> List.filter (fun e -> e.IsTypeDefinition) + let nestedModules = m.NestedEntities |> List.filter (fun e -> not e.IsTypeDefinition) - if not m.NestedTypes.IsEmpty then + if not nestedTypes.IsEmpty then b [] [!! "Declared Types"] table [] [ tr [] [ th [ Width "35%" ] [!!"Type"] th [ Width "65%"] [!!"Description"] ] - for t in m.NestedTypes do + for t in nestedTypes do tr [] [ - td [] [a [Href ($"%s{t.UrlName}.html")] [!! t.Name ]] + td [] [a [Href ($"%s{t.UrlBaseName}.html")] [!! t.Name ]] td [] [!! (getComment t.Comment)] ] ] br [] - if not m.NestedModules.IsEmpty then + if not nestedModules.IsEmpty then b [] [!! "Declared Modules"] table [] [ tr [] [ th [ Width "35%" ] [!!"Module"] th [ Width "65%"] [!!"Description"] ] - for t in m.NestedModules do + for t in nestedModules do tr [] [ - td [] [a [Href ($"%s{t.UrlName}.html")] [!! t.Name ]] + td [] [a [Href ($"%s{t.UrlBaseName}.html")] [!! t.Name ]] td [] [!! (getComment t.Comment)] ] ] br [] - if not m.ValuesAndFuncs.IsEmpty then + if not (m.ValuesAndFuncs : ApiDocMember list).IsEmpty then b [] [!! "Values and Functions"] table [] [ tr [] [ @@ -179,7 +194,7 @@ let generateModule ctx (page: ApiPageInfo) = ] br [] - if not m.TypeExtensions.IsEmpty then + if not (m.TypeExtensions : ApiDocMember list).IsEmpty then b [] [!! "Type Extensions"] table [] [ tr [] [ @@ -189,45 +204,45 @@ let generateModule ctx (page: ApiPageInfo) = yield! m.TypeExtensions |> List.map formatMember ] ] - m.UrlName, Layout.layout ctx [body] m.Name + m.UrlBaseName, Layout.layout ctx [body] m.Name + +let generateNamespace ctx (allTypes: ApiPageInfo list) (ns: ApiDocNamespace) = + let namespaceTypes = allTypes |> List.filter (fun t -> t.NamespaceName = ns.Name && t.ParentName = ns.Name) -let generateNamespace ctx (n: Namespace) = let body = div [Class "api-page"] [ - h2 [] [!!n.Name] - - if not n.Types.IsEmpty then + h2 [] [!!ns.Name] + if not namespaceTypes.IsEmpty then b [] [!! "Declared Types"] table [] [ tr [] [ th [ Width "35%" ] [!!"Type"] th [ Width "65%"] [!!"Description"] ] - for t in n.Types do + for t in namespaceTypes do tr [] [ - td [] [a [Href ($"%s{t.UrlName}.html")] [!! t.Name ]] - td [] [!!(getComment t.Comment)] + td [] [a [Href ($"%s{t.Info.UrlBaseName}.html")] [!! t.Info.Name ]] + td [] [!! (getComment t.Info.Comment)] ] ] br [] - if not n.Modules.IsEmpty then - + if not (ns.Entities).IsEmpty then b [] [!! "Declared Modules"] table [] [ tr [] [ th [ Width "35%" ] [!!"Module"] th [ Width "65%"] [!!"Description"] ] - for t in n.Modules do + for t in ns.Entities do tr [] [ - td [] [a [Href ($"%s{t.UrlName}.html")] [!! t.Name ]] + td [] [a [Href ($"%s{t.UrlBaseName}.html")] [!! t.Name ]] td [] [!! (getComment t.Comment)] ] ] ] - n.Name, Layout.layout ctx [body] (n.Name) + ns.Name, Layout.layout ctx [body] (ns.Name) let generate' (ctx : SiteContents) = @@ -238,10 +253,10 @@ let generate' (ctx : SiteContents) = all |> Seq.toList |> List.collect (fun n -> - let name = n.GeneratorOutput.AssemblyGroup.Name + let name = n.GeneratorOutput.Collection.CollectionName let namespaces = - n.GeneratorOutput.AssemblyGroup.Namespaces - |> List.map (generateNamespace ctx) + n.GeneratorOutput.Collection.Namespaces + |> List.map (generateNamespace ctx n.Types) let modules = n.Modules diff --git a/docs/generators/lunr.fsx b/docs/generators/lunr.fsx index 35c98b246..a5f4094f8 100644 --- a/docs/generators/lunr.fsx +++ b/docs/generators/lunr.fsx @@ -1,15 +1,15 @@ -#r "../_lib/Fornax.Core.dll" -#r "../../packages/docs/Newtonsoft.Json/lib/netstandard2.0/Newtonsoft.Json.dll" -#r "../../packages/docs/FSharp.Formatting/lib/netstandard2.0/FSharp.MetadataFormat.dll" +#r "nuget: Fornax.Core, 0.16.0-beta002" +#r "nuget: FSharp.Formatting, 20.0.1" + #if !FORNAX #load "../loaders/contentloader.fsx" #load "../loaders/apirefloader.fsx" #load "../loaders/globalloader.fsx" - #endif open Apirefloader -open FSharp.MetadataFormat +open FSharp.Formatting.ApiDocs +open System.Text.Json type Entry = { @@ -18,65 +18,64 @@ type Entry = { content: string } let generate (ctx : SiteContents) (projectRoot: string) (page: string) = - let siteInfo = ctx.TryGetValue().Value - let rootUrl = siteInfo.root_url + let siteInfo = ctx.TryGetValue() + let rootUrl = + match siteInfo with + | Some info -> info.root_url + | None -> "" let pages = ctx.TryGetValues () |> Option.defaultValue Seq.empty let entries = - pages - |> Seq.map (fun n -> - {uri = rootUrl + "/" + n.link.Replace("content/", ""); title = n.title; content = n.text} - ) + pages + |> Seq.map (fun n -> + {uri = rootUrl + "/" + n.link.Replace("content/", ""); title = n.title; content = n.text} + ) let all = ctx.TryGetValues() let refs = - match all with - | None -> [] - | Some all -> - all - |> Seq.toList - |> List.collect (fun n -> - let generatorOutput = n.GeneratorOutput - let allModules = n.Modules - let allTypes = n.Types + match all with + | None -> [] + | Some all -> + all + |> Seq.toList + |> List.collect (fun n -> + let generatorOutput = n.GeneratorOutput + let allModules = n.Modules + let allTypes = n.Types - let gen = - let ctn = - let namespaces = generatorOutput.AssemblyGroup.Namespaces |> Seq.map (fun n -> n.Name) |> String.concat " " - $"%s{generatorOutput.AssemblyGroup.Name} \n %s{namespaces}" - {uri = $"{rootUrl}/reference/%s{n.Label}/index.html"; title = $"%s{n.Label} - API Reference"; content = ctn } + let gen = + let ctn = + let namespaces = generatorOutput.Collection.Namespaces |> Seq.map (fun n -> n.Name) |> String.concat " " + $"%s{generatorOutput.Collection.CollectionName} \n %s{namespaces}" + {uri = $"{rootUrl}/reference/%s{n.Label}/index.html"; title = $"%s{n.Label} - API Reference"; content = ctn } - let mdlsGen = - allModules - |> Seq.map (fun m -> - let m = m.Info - let cnt = - sprintf "%s \n %s \n %s \n %s \n %s \n %s" - m.Name - m.Comment.FullText - (m.NestedModules |> List.map (fun m -> m.Name + " " + m.Comment.FullText ) |> String.concat " ") - (m.NestedTypes |> List.map (fun m -> m.Name + " " + m.Comment.FullText ) |> String.concat " ") - (m.ValuesAndFuncs |> List.map (fun m -> m.Name + " " + m.Comment.FullText ) |> String.concat " ") - (m.TypeExtensions |> List.map (fun m -> m.Name + " " + m.Comment.FullText ) |> String.concat " ") + let mdlsGen = + allModules + |> Seq.map (fun m -> + let m = m.Info + let cnt = + sprintf "%s \n %s \n %s" + m.Name + (m.Comment.Xml |> Option.map string |> Option.defaultValue "") + (m.NestedEntities |> List.map (fun m -> $"{m.Name} {m.Comment.Xml}") |> String.concat " ") + {uri = $"{rootUrl}/reference/%s{n.Label}/%s{m.UrlBaseName}.html"; title = m.Name; content = cnt } + ) - {uri = $"{rootUrl}/reference/%s{n.Label}/%s{m.UrlName}.html"; title = m.Name; content = cnt } - ) + let tsGen = + allTypes + |> Seq.map (fun m -> + let m = m.Info + let cnt = + let getComment xml = xml |> Option.map string |> Option.defaultValue "" + let allMembers = m.AllMembers |> List.map (fun m -> $"{m.Name} {m.Comment.Xml |> getComment}" ) |> String.concat " " + $"%s{m.Name} \n %s{m.Comment.Xml |> getComment} \n %s{allMembers}" - let tsGen = - allTypes - |> Seq.map (fun m -> - let m = m.Info - let cnt = - let allMembers = m.AllMembers |> List.map (fun m -> $"{m.Name} {m.Comment.FullText}" ) |> String.concat " " - $"%s{m.Name} \n %s{m.Comment.FullText} \n %s{allMembers}" - - - {uri = $"{rootUrl}/reference/%s{n.Label}/%s{m.UrlName}.html"; title = m.Name; content = cnt } - ) - [yield! entries; gen; yield! mdlsGen; yield! tsGen] - ) + {uri = $"{rootUrl}/reference/%s{n.Label}/%s{m.UrlBaseName}.html"; title = m.Name; content = cnt } + ) + [yield! entries; gen; yield! mdlsGen; yield! tsGen] + ) [|yield! entries; yield! refs|] - |> Newtonsoft.Json.JsonConvert.SerializeObject + |> JsonSerializer.Serialize diff --git a/docs/generators/page.fsx b/docs/generators/page.fsx index e07291238..6df4fce13 100644 --- a/docs/generators/page.fsx +++ b/docs/generators/page.fsx @@ -1,4 +1,4 @@ -#r "../_lib/Fornax.Core.dll" +#r "nuget: Fornax.Core, 0.16.0-beta002" #load "partials/layout.fsx" open Html diff --git a/docs/generators/partials/footer.fsx b/docs/generators/partials/footer.fsx index 74f47a586..01f639642 100644 --- a/docs/generators/partials/footer.fsx +++ b/docs/generators/partials/footer.fsx @@ -1,4 +1,4 @@ -#r "../../_lib/Fornax.Core.dll" +#r "nuget: Fornax.Core, 0.16.0-beta002" #if !FORNAX #load "../../loaders/contentloader.fsx" #load "../../loaders/pageloader.fsx" @@ -14,8 +14,8 @@ let footer (ctx : SiteContents) = let rootUrl = siteInfo.root_url [ - div [Custom("style", "left: -1000px; overflow: scroll; position: absolute; top: -1000px; border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;")] [ - div [Custom("style", "border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;")] [] + div [HtmlProperties.Custom("style", "left: -1000px; overflow: scroll; position: absolute; top: -1000px; border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;")] [ + div [HtmlProperties.Custom("style", "border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;")] [] ] script [Src (rootUrl + "/static/js/clipboard.min.js")] [] script [Src (rootUrl + "/static/js/perfect-scrollbar.min.js")] [] diff --git a/docs/generators/partials/header.fsx b/docs/generators/partials/header.fsx index be7ad2e7e..e412d44bb 100644 --- a/docs/generators/partials/header.fsx +++ b/docs/generators/partials/header.fsx @@ -1,4 +1,4 @@ -#r "../../_lib/Fornax.Core.dll" +#r "nuget: Fornax.Core, 0.16.0-beta002" #if !FORNAX #load "../../loaders/contentloader.fsx" #load "../../loaders/pageloader.fsx" diff --git a/docs/generators/partials/layout.fsx b/docs/generators/partials/layout.fsx index 62262c067..bf61ca3d5 100644 --- a/docs/generators/partials/layout.fsx +++ b/docs/generators/partials/layout.fsx @@ -1,4 +1,4 @@ -#r "../../_lib/Fornax.Core.dll" +#r "nuget: Fornax.Core, 0.16.0-beta002" #if !FORNAX #load "../../loaders/contentloader.fsx" #load "../../loaders/pageloader.fsx" @@ -45,7 +45,7 @@ let layout (ctx : SiteContents) bodyCnt (page: string) = div [ Class "padding highlightable"] [ div [Id "body-inner"] [ span [Id "sidebar-toggle-span"] [ - a [Href "#"; Id "sidebar-toggle"; Custom("data-sidebar-toggle", "") ] [ + a [Href "#"; Id "sidebar-toggle"; HtmlProperties.Custom("data-sidebar-toggle", "") ] [ i [Class "fas fa-bars"] [] !! " navigation" ] diff --git a/docs/generators/partials/menu.fsx b/docs/generators/partials/menu.fsx index 26a056f5c..ae0a624fa 100644 --- a/docs/generators/partials/menu.fsx +++ b/docs/generators/partials/menu.fsx @@ -1,4 +1,4 @@ -#r "../../_lib/Fornax.Core.dll" +#r "nuget: Fornax.Core, 0.16.0-beta002" #if !FORNAX #load "../../loaders/apirefloader.fsx" #load "../../loaders/contentloader.fsx" @@ -8,14 +8,16 @@ open Html - let menu (ctx : SiteContents) (page: string) = let shortcuts = ctx.GetValues () - let all = ctx.GetValues() + let all = ctx.TryGetValues() |> Option.defaultValue Seq.empty let content = ctx.GetValues () - let siteInfo = ctx.TryGetValue().Value - let rootUrl = siteInfo.root_url + let siteInfo = ctx.TryGetValue() + let rootUrl = + match siteInfo with + | Some info -> info.root_url + | None -> "" let group = content |> Seq.tryFind (fun n -> n.title = page) |> Option.map (fun n -> n.category) @@ -29,6 +31,25 @@ let menu (ctx : SiteContents) (page: string) = |> Seq.filter (fun n -> n.category = Contentloader.HowTo && not n.hide_menu ) |> Seq.sortBy (fun n -> n.menu_order) + let apiReferencesSection = + if Seq.isEmpty all then + // If no API references are available, don't show the section + [] + else + [ + li [Class "dd-item parent"] [ + a [if group = None then Class "active" else Class ""] [!! "API References"] + ul [Class "child"] [ + for r in all -> + li [Class "dd-item"] [ + a [Href (rootUrl + "/reference/" + r.Label + "/index.html"); if r.Label = page then Class "active" else Class "" ] [ + !! r.Label + ] + ] + ] + ] + ] + let menuHeader = [ li [Class "dd-item"] [ @@ -45,17 +66,7 @@ let menu (ctx : SiteContents) (page: string) = ] ] ] - li [Class "dd-item parent"] [ - a [if group = None then Class "active" else Class ""] [!! "API References"] - ul [Class "child"] [ - for r in all -> - li [Class "dd-item"] [ - a [Href (rootUrl + "/reference/" + r.Label + "/index.html"); if r.Label = page then Class "active" else Class "" ] [ - !! r.Label - ] - ] - ] - ] + yield! apiReferencesSection ] let renderShortcuts = @@ -78,16 +89,20 @@ let menu (ctx : SiteContents) (page: string) = !! """

Built with Fornax""" ] + let title = + match siteInfo with + | Some info -> info.title + | None -> "FSharpLint" nav [Id "sidebar"] [ div [Id "header-wrapper"] [ div [Id "header"] [ - h2 [Id "logo"] [!! siteInfo.title] + h2 [Id "logo"] [!! title] ] div [Class "searchbox"] [ - label [Custom("for", "search-by")] [i [Class "fas fa-search"] []] - input [Custom ("data-search-input", ""); Id "search-by"; Type "search"; Placeholder "Search..."] - span [Custom ("data-search-clear", "")] [i [Class "fas fa-times"] []] + label [HtmlProperties.Custom ("for", "search-by")] [i [Class "fas fa-search"] []] + input [HtmlProperties.Custom ("data-search-input", ""); Id "search-by"; Type "search"; Placeholder "Search..."] + span [HtmlProperties.Custom ("data-search-clear", "")] [i [Class "fas fa-times"] []] ] script [Type "text/javascript"; Src (rootUrl + "/static/js/lunr.min.js")] [] script [Type "text/javascript"; Src (rootUrl + "/static/js/auto-complete.js")] [] diff --git a/docs/loaders/apirefloader.fsx b/docs/loaders/apirefloader.fsx index 0e75204ed..7eeeaad5f 100644 --- a/docs/loaders/apirefloader.fsx +++ b/docs/loaders/apirefloader.fsx @@ -1,9 +1,10 @@ -#r "../_lib/Fornax.Core.dll" -#r "../../packages/docs/FSharp.Formatting/lib/netstandard2.0/FSharp.MetadataFormat.dll" +#r "nuget: Fornax.Core, 0.16.0-beta002" +#r "nuget: FSharp.Formatting, 20.0.1" open System open System.IO -open FSharp.MetadataFormat +open FSharp.Formatting.ApiDocs +open FSharp.Formatting.Templating type ApiPageInfo<'a> = { ParentName: string @@ -15,58 +16,101 @@ type ApiPageInfo<'a> = { type AssemblyEntities = { Label: string - Modules: ApiPageInfo list - Types: ApiPageInfo list - GeneratorOutput: GeneratorOutput + Modules: ApiPageInfo list + Types: ApiPageInfo list + GeneratorOutput: ApiDocModel } -let rec collectModules pn pu nn nu (m: Module) = +let rec collectModules pn pu nn nu (m: ApiDocEntity) = [ - yield { ParentName = pn; ParentUrlName = pu; NamespaceName = nn; NamespaceUrlName = nu; Info = m} - yield! m.NestedModules |> List.collect (collectModules m.Name m.UrlName nn nu ) + yield { ParentName = pn; ParentUrlName = pu; NamespaceName = nn; NamespaceUrlName = nu; Info = m} + yield! m.NestedEntities |> List.collect (collectModules m.Name m.UrlBaseName nn nu) ] let loader (projectRoot: string) (siteContet: SiteContents) = try - let dlls = - [ - "FSharpLint.Core", Path.Combine(projectRoot, "..", "build", "FSharpLint.Core.dll") + // We need the console location as it contains all the dependencies + let projectDir = Path.Combine(projectRoot, "..", "src", "FSharpLint.Console") + let dotNetMoniker = "net9.0" + let projectName = "FSharpLint.Console" + let projectArtifactName = "FSharpLint.Core.dll" + // Try multiple possible locations for the assembly + let possiblePaths = [ + // CI build output + Path.Combine("..", "build", projectArtifactName) + // Release build + Path.Combine(projectDir, "bin", "Release", dotNetMoniker, projectArtifactName) + // Debug build + Path.Combine(projectDir, "bin", "Debug", dotNetMoniker, projectArtifactName) + // Default build output (no custom output path) + Path.Combine(projectDir, "bin", "Release", projectArtifactName) + Path.Combine(projectDir, "bin", "Debug", projectArtifactName) ] - let libs = - [ - Path.Combine (projectRoot, "..", "build") - ] - for (label, dll) in dlls do - let output = MetadataFormat.Generate(dll, markDownComments = true, publicOnly = true, libDirs = libs) - let allModules = - output.AssemblyGroup.Namespaces - |> List.collect (fun n -> - List.collect (collectModules n.Name n.Name n.Name n.Name) n.Modules - ) + let foundDll = possiblePaths |> List.tryFind File.Exists + + match foundDll with + | Some dllPath -> + let binDir = Path.GetDirectoryName(dllPath) + printfn $"Found assembly at: %s{dllPath}" + printfn $"Using lib directory: %s{binDir}" + + let libs = [binDir] + + // Try to load with minimal dependencies first + let inputs = [ApiDocInput.FromFile(dllPath, mdcomments = true)] + try + let output = ApiDocs.GenerateModel(inputs, projectName, [], libDirs = libs) - let allTypes = - [ - yield! - output.AssemblyGroup.Namespaces + let allModules = + output.Collection.Namespaces |> List.collect (fun n -> - n.Types |> List.map (fun t -> {ParentName = n.Name; ParentUrlName = n.Name; NamespaceName = n.Name; NamespaceUrlName = n.Name; Info = t} ) + List.collect (collectModules n.Name n.Name n.Name n.Name) n.Entities ) - yield! - allModules - |> List.collect (fun n -> - n.Info.NestedTypes |> List.map (fun t -> {ParentName = n.Info.Name; ParentUrlName = n.Info.UrlName; NamespaceName = n.NamespaceName; NamespaceUrlName = n.NamespaceUrlName; Info = t}) ) - ] - let entities = { - Label = label - Modules = allModules - Types = allTypes - GeneratorOutput = output - } - siteContet.Add entities + + let allTypes = + [ + yield! + output.Collection.Namespaces + |> List.collect (fun n -> + n.Entities |> List.choose (fun t -> + if t.IsTypeDefinition then + Some {ParentName = n.Name; ParentUrlName = n.Name; NamespaceName = n.Name; NamespaceUrlName = n.Name; Info = t} + else + None) + ) + yield! + allModules + |> List.collect (fun n -> + // Get nested types from nested entities + n.Info.NestedEntities + |> List.choose (fun e -> + if e.IsTypeDefinition then + Some {ParentName = n.Info.Name; ParentUrlName = n.Info.UrlBaseName; NamespaceName = n.NamespaceName; NamespaceUrlName = n.NamespaceUrlName; Info = e} + else + None) + ) + ] + let entities = { + Label = "FSharpLint.Core" + Modules = allModules + Types = allTypes + GeneratorOutput = output + } + siteContet.Add entities + printfn $"Successfully loaded API documentation for {projectName}" + with + | ex -> + printfn $"Failed to generate API docs from %s{dllPath}: %A{ex}" + printfn "Continuing without API documentation..." + | None -> + printfn $"Warning: Could not find {projectArtifactName} in any of the expected locations:" + possiblePaths |> List.iter (printfn " - %s") + printfn "API documentation will not be generated." + Environment.Exit 1 with | ex -> - printfn "%A" ex - + printfn "Error in API reference loader: %A" ex + Environment.Exit 1 siteContet diff --git a/docs/loaders/contentloader.fsx b/docs/loaders/contentloader.fsx index c101a5ca3..6a9f6d45c 100644 --- a/docs/loaders/contentloader.fsx +++ b/docs/loaders/contentloader.fsx @@ -1,8 +1,7 @@ -open System -#r "../_lib/Fornax.Core.dll" -#r "../../packages/docs/Markdig/lib/netstandard2.0/Markdig.dll" - +#r "nuget: Fornax.Core, 0.16.0-beta002" +#r "nuget: Markdig, 0.41.3" open Markdig +open System open System.IO type PostConfig = { diff --git a/docs/loaders/copyloader.fsx b/docs/loaders/copyloader.fsx index e2b892f08..7d84a0edf 100644 --- a/docs/loaders/copyloader.fsx +++ b/docs/loaders/copyloader.fsx @@ -1,4 +1,4 @@ -#r "../_lib/Fornax.Core.dll" +#r "nuget: Fornax.Core, 0.16.0-beta002" open System.IO @@ -15,4 +15,4 @@ let loader (projectRoot: string) (siteContet: SiteContents) = for filePath in Directory.GetFiles(intputPath, "*.*", SearchOption.AllDirectories) do File.Copy(filePath, filePath.Replace(intputPath, outputPath), true) - siteContet \ No newline at end of file + siteContet diff --git a/docs/loaders/globalloader.fsx b/docs/loaders/globalloader.fsx index 619eefbd9..c475af16e 100644 --- a/docs/loaders/globalloader.fsx +++ b/docs/loaders/globalloader.fsx @@ -1,4 +1,4 @@ -#r "../_lib/Fornax.Core.dll" +#r "nuget: Fornax.Core, 0.16.0-beta002" type SiteInfo = { title: string diff --git a/docs/loaders/pageloader.fsx b/docs/loaders/pageloader.fsx index 8a0a4dda0..070426b0f 100644 --- a/docs/loaders/pageloader.fsx +++ b/docs/loaders/pageloader.fsx @@ -1,5 +1,4 @@ -#r "../_lib/Fornax.Core.dll" - +#r "nuget: Fornax.Core, 0.16.0-beta002" type Shortcut = { title: string diff --git a/global.json b/global.json index 5461033ae..a4155b168 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,6 @@ { "sdk": { - "rollForward": "minor" + "version": "9.0.201", + "rollForward": "disable" } }