FSharp.Formatting


BinderScriptNotebook

API Documentation Generation

The command-line tool fsdocs can be used to generate documentation for F# libraries with XML comments. The documentation is normally built using fsdocs build and developed using fsdocs watch. For the former the output will be placed in output\reference by default.

Selected projects

fsdocs automatically selects the projects and "cracks" the project files for information

    <PropertyGroup>
      <GenerateDocumentationFile>true</GenerateDocumentationFile>
    </PropertyGroup>

Templates

The HTML is built by instantiating a template. The template used is the first of:

Usually the same template can be used as for other content.

Classic XML Doc Comments

XML Doc Comments may use the normal F# and C# XML doc standards.

The tags that form the core of the XML doc specification are:

<c>	<para>	<see>*	<value>
<code>	<param>*	<seealso>*
<example>	<paramref>	<summary>
<exception>*	<permission>*	<typeparam>*
<include>*	<remarks>	<typeparamref>
<list>	<inheritdoc>	<returns>

In addition, you may also use the Recommended XML doc extensions for F# documentation tooling.

An example of an XML documentation comment, assuming the code is in namespace TheNamespace:

/// <summary>
///   A module
/// </summary>
///
/// <namespacedoc>
///   <summary>A namespace to remember</summary>
///
///   <remarks>More on that</remarks>
/// </namespacedoc>
///
module SomeModule =
    /// <summary>
    ///   Some actual comment
    ///   <para>Another paragraph, see  <see cref="T:TheNamespace.SomeType"/>. </para>
    /// </summary>
    ///
    /// <param name="x">The input</param>
    ///
    /// <returns>The output</returns>
    ///
    /// <example>
    ///   Try using
    ///   <code>
    ///      open TheNamespace
    ///      SomeModule.a
    ///   </code>
    /// </example>
    ///
    /// <category>Foo</category>
    let someFunction x = 42 + x

/// <summary>
///   A type, see  <see cref="T:TheNamespace.SomeModule"/> and
///  <see cref="M:TheNamespace.SomeModule.someFunction"/>.
/// </summary>
///
type SomeType() =
    member x.P = 1

Like types, members are referred to by xml doc sig. These must currently be precise as the F# compiler doesn't elaborate these references from simpler names:

type Class2() =
    member this.Property = "more"
    member this.Method0() = "more"
    member this.Method1(c: string) = "more"
    member this.Method2(c: string, o: obj) = "more"

/// <see cref="P:TheNamespace.Class2.Property" />
/// and <see cref="M:TheNamespace.Class2.OtherMethod0" />
/// and <see cref="M:TheNamespace.Class2.Method1(System.String)" />
/// and <see cref="M:TheNamespace.Class2.Method2(System.String,System.Object)" />
let referringFunction1 () = "result"

Generic types are referred to by .NET compiled name, e.g.

type GenericClass2<'T>() =
    member this.Property = "more"

    member this.NonGenericMethod(_c: 'T) = "more"

    member this.GenericMethod(_c: 'T, _o: 'U) = "more"

/// See <see cref="T:TheNamespace.GenericClass2`1" />
/// and <see cref="P:TheNamespace.GenericClass2`1.Property" />
/// and <see cref="M:TheNamespace.GenericClass2`1.NonGenericMethod(`0)" />
/// and <see cref="M:TheNamespace.GenericClass2`1.GenericMethod``1(`0,``0)" />
let referringFunction2 () = "result"

(*

## Go to Source links

'fsdocs' normally automatically adds GitHub links to each functions, values and class members for further reference.

This is normally done automatically based on the following settings:

    <RepositoryUrl>https://github.com/...</RepositoryUrl>
    <RepositoryBranch>...</RepositoryBranch>
    <RepositoryType>git</RepositoryType>

If your source is not built from the same project where you are building documentation then
you may need these settings:

    <FsDocsSourceRepository>...</FsDocsSourceRepository> -- the URL for the root of the source
    <FsDocsSourceFolder>...</FsDocsSourceFolder>         -- the root soure folder at time of build

It is assumed that `sourceRepo` and `sourceFolder` have synchronized contents.

## Markdown Comments

You can use Markdown instead of XML in `///` comments. If you do, you should set `<UsesMarkdownComments>` in
your F# project file.

> Note: Markdown Comments are not supported in all F# IDE tooling.

### Adding cross-type links to modules and types in the same assembly

You can automatically add cross-type links to the documentation pages of other modules and types in the same assembly.
You can do this in two different ways:

* Add a [markdown inline link](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#links) were the link
title is the name of the type you want to link.

      /// this will generate a link to [Foo.Bar] documentation

* Add a [Markdown inline code](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code) (using
back-ticks) where the code is the name of the type you want to link.

      /// This will also generate a link to `Foo.Bar` documentation

You can use either the full name (including namespace and module) or the simple name of a type.
If more than one type is found with the same name the link will not be generated.
If a type with the given name is not found in the same assembly the link will not be generated.
*)

/// Contains two types [Bar] and [Foo.Baz]
module Foo =

    /// Bar is just an `int` and belongs to module [Foo]
    type Bar = int

    /// Baz contains a `Foo.Bar` as its `id`
    type Baz = { id: Bar }

    /// This function operates on `Baz` types.
    let f (b: Baz) = b.id * 42

/// Referencing [Foo3] will not generate a link as there is no type with the name `Foo3`
module Foo3 =

    /// This is not the same type as `Foo.Bar`
    type Bar = double

    /// Using the simple name for [Bar] will fail to create a link because the name is duplicated in
    /// [Foo.Bar] and in [Foo3.Bar]. In this case, using the full name works.
    let f2 b = b * 50

Markdown Comments: Excluding APIs from the docs

If you want to exclude modules or functions from the API docs you can use the [omit] tag. It needs to be set on a separate tripple-slashed line, but it could be either the first or the last:

/// Some actual comment
module Bar =
    let a = 42

Building library documentation programmatically

You can build library documentation programatically using the functionality in the ApiDocs type. To do this, load the assembly and open necessary namespaces:

#r "FSharp.Formatting.ApiDocs.dll"

open FSharp.Formatting.ApiDocs
open System.IO

For example the ApiDocs.GenerateHtml method:

let file = Path.Combine(root, "bin/YourLibrary.dll")

let input = ApiDocInput.FromFile(file)

ApiDocs.GenerateHtml(
    [ input ],
    output = Path.Combine(root, "output"),
    collectionName = "YourLibrary",
    template = Path.Combine(root, "templates", "template.html"),
    substitutions = []
)
val root: string
type 'T list = List<'T>
<summary>The type of immutable singly-linked lists. </summary>
<remarks>See the <see cref="T:Microsoft.FSharp.Collections.ListModule" /> module for further operations related to lists. Use the constructors <c>[]</c> and <c>::</c> (infix) to create values of this type, or the notation <c>[1; 2; 3]</c>. Use the values in the <c>List</c> module to manipulate values of this type, or pattern match against the values directly. See also <a href="https://docs.microsoft.com/dotnet/fsharp/language-reference/lists">F# Language Guide - Lists</a>. </remarks>
val someFunction: x: int -> int
 <summary>
   Some actual comment
   <para>Another paragraph, see <see cref="T:TheNamespace.SomeType"/>. </para>
 </summary>

 <param name="x">The input</param>

 <returns>The output</returns>

 <example>
   Try using
   <code>
      open TheNamespace
      SomeModule.a
   </code>
 </example>

 <category>Foo</category>
val x: int
Multiple items
type SomeType = new: unit -> SomeType member P: int
 <summary>
   A type, see <see cref="T:TheNamespace.SomeModule"/> and
  <see cref="M:TheNamespace.SomeModule.someFunction"/>.
 </summary>


--------------------
new: unit -> SomeType
val x: SomeType
member SomeType.P: int
Multiple items
type Class2 = new: unit -> Class2 member Method0: unit -> string member Method1: c: string -> string member Method2: c: string * o: obj -> string member Property: string

--------------------
new: unit -> Class2
val this: Class2
val c: string
Multiple items
val string: value: 'T -> string
<summary>Converts the argument to a string using <c>ToString</c>.</summary>
<remarks>For standard integer and floating point values the and any type that implements <c>IFormattable</c><c>ToString</c> conversion uses <c>CultureInfo.InvariantCulture</c>. </remarks>
<param name="value">The input value.</param>
<returns>The converted string.</returns>
<example id="string-example"><code lang="fsharp"></code></example>


--------------------
type string = System.String
<summary>An abbreviation for the CLI type <see cref="T:System.String" />.</summary>
<category>Basic Types</category>
val o: obj
type obj = System.Object
<summary>An abbreviation for the CLI type <see cref="T:System.Object" />.</summary>
<category>Basic Types</category>
val referringFunction1: unit -> string
 <see cref="P:TheNamespace.Class2.Property" />
 and <see cref="M:TheNamespace.Class2.OtherMethod0" />
 and <see cref="M:TheNamespace.Class2.Method1(System.String)" />
 and <see cref="M:TheNamespace.Class2.Method2(System.String,System.Object)" />
Multiple items
type GenericClass2<'T> = new: unit -> GenericClass2<'T> member GenericMethod: _c: 'T * _o: 'U -> string member NonGenericMethod: _c: 'T -> string member Property: string

--------------------
new: unit -> GenericClass2<'T>
val this: GenericClass2<'T>
val _c: 'T
val _o: 'U
val referringFunction2: unit -> string
 See <see cref="T:TheNamespace.GenericClass2`1" />
 and <see cref="P:TheNamespace.GenericClass2`1.Property" />
 and <see cref="M:TheNamespace.GenericClass2`1.NonGenericMethod(`0)" />
 and <see cref="M:TheNamespace.GenericClass2`1.GenericMethod``1(`0,``0)" />
[<Struct>] type Bar = int
 Bar is just an `int` and belongs to module [Foo]
Multiple items
val int: value: 'T -> int (requires member op_Explicit)
<summary>Converts the argument to signed 32-bit integer. This is a direct conversion for all primitive numeric types. For strings, the input is converted using <c>Int32.Parse()</c> with InvariantCulture settings. Otherwise the operation requires an appropriate static conversion method on the input type.</summary>
<param name="value">The input value.</param>
<returns>The converted int</returns>
<example id="int-example"><code lang="fsharp"></code></example>


--------------------
[<Struct>] type int = int32
<summary>An abbreviation for the CLI type <see cref="T:System.Int32" />.</summary>
<category>Basic Types</category>


--------------------
type int<'Measure> = int
<summary>The type of 32-bit signed integer numbers, annotated with a unit of measure. The unit of measure is erased in compiled code and when values of this type are analyzed using reflection. The type is representationally equivalent to <see cref="T:System.Int32" />.</summary>
<category>Basic Types with Units of Measure</category>
type Baz = { id: Bar }
 Baz contains a `Foo.Bar` as its `id`
Baz.id: Bar
val f: b: Baz -> Bar
 This function operates on `Baz` types.
val b: Baz
[<Struct>] type Bar = double
 This is not the same type as `Foo.Bar`
Multiple items
val double: value: 'T -> double (requires member op_Explicit)
<summary>Converts the argument to 64-bit float.</summary>
<remarks>This is a direct conversion for all primitive numeric types. For strings, the input is converted using <c>Double.Parse()</c> with InvariantCulture settings. Otherwise the operation requires and invokes a <c>ToDouble</c> method on the input type.</remarks>
<example id="double-1"><code lang="fsharp"> double 45 </code> Evaluates to <c>45.0</c>. </example>
<example id="double-2"><code lang="fsharp"> double 12.3f </code> Evaluates to <c>12.30000019</c>. </example>


--------------------
[<Struct>] type double = System.Double
<summary>An abbreviation for the CLI type <see cref="T:System.Double" />. Identical to <see cref="T:Microsoft.FSharp.Core.float" />.</summary>
<category>Basic Types</category>


--------------------
type double<'Measure> = float<'Measure>
<summary>The type of double-precision floating point numbers, annotated with a unit of measure. The unit of measure is erased in compiled code and when values of this type are analyzed using reflection. The type is representationally equivalent to <see cref="T:System.Double" />.</summary>
<category index="6">Basic Types with Units of Measure</category>
val f2: b: int -> int
 Using the simple name for [Bar] will fail to create a link because the name is duplicated in
 [Foo.Bar] and in [Foo3.Bar]. In this case, using the full name works.
val b: int
val a: int
Multiple items
namespace FSharp

--------------------
namespace Microsoft.FSharp
namespace FSharp.Formatting
namespace FSharp.Formatting.ApiDocs
namespace System
namespace System.IO
val file: string
type Path = static member ChangeExtension: path: string * extension: string -> string static member Combine: path1: string * path2: string -> string + 3 overloads static member EndsInDirectorySeparator: path: ReadOnlySpan<char> -> bool + 1 overload static member GetDirectoryName: path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload static member GetExtension: path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload static member GetFileName: path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload static member GetFileNameWithoutExtension: path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload static member GetFullPath: path: string -> string + 1 overload static member GetInvalidFileNameChars: unit -> char[] static member GetInvalidPathChars: unit -> char[] ...
<summary>Performs operations on <see cref="T:System.String" /> instances that contain file or directory path information. These operations are performed in a cross-platform manner.</summary>
Path.Combine([<System.ParamArray>] paths: string[]) : string
Path.Combine(path1: string, path2: string) : string
Path.Combine(path1: string, path2: string, path3: string) : string
Path.Combine(path1: string, path2: string, path3: string, path4: string) : string
val input: ApiDocInput
type ApiDocInput = { Path: string XmlFile: string option SourceFolder: string option SourceRepo: string option Substitutions: Substitutions option MarkdownComments: bool Warn: bool PublicOnly: bool } static member FromFile: assemblyPath: string * ?mdcomments: bool * ?substitutions: Substitutions * ?sourceRepo: string * ?sourceFolder: string * ?publicOnly: bool * ?warn: bool -> ApiDocInput
<summary> Represents an input assembly for API doc generation </summary>
static member ApiDocInput.FromFile: assemblyPath: string * ?mdcomments: bool * ?substitutions: FSharp.Formatting.Templating.Substitutions * ?sourceRepo: string * ?sourceFolder: string * ?publicOnly: bool * ?warn: bool -> ApiDocInput
type ApiDocs = static member GenerateHtml: inputs: ApiDocInput list * output: string * collectionName: string * substitutions: Substitutions * ?template: string * ?root: string * ?qualify: bool * ?libDirs: string list * ?otherFlags: string list * ?urlRangeHighlight: (Uri -> int -> int -> string) * ?onError: (string -> unit) -> ApiDocModel * ApiDocsSearchIndexEntry[] static member GenerateMarkdown: inputs: ApiDocInput list * output: string * collectionName: string * substitutions: Substitutions * ?template: string * ?root: string * ?qualify: bool * ?libDirs: string list * ?otherFlags: string list * ?urlRangeHighlight: (Uri -> int -> int -> string) * ?onError: (string -> unit) -> ApiDocModel * ApiDocsSearchIndexEntry[] static member GenerateModel: inputs: ApiDocInput list * collectionName: string * substitutions: Substitutions * ?qualify: bool * ?libDirs: string list * ?otherFlags: string list * ?root: string * ?urlRangeHighlight: (Uri -> int -> int -> string) * ?onError: (string -> unit) * ?extension: ApiDocFileExtensions -> ApiDocModel static member SearchIndexEntriesForModel: model: ApiDocModel -> ApiDocsSearchIndexEntry[]
<summary> This type exposes the functionality for producing documentation model from `dll` files with associated `xml` files generated by the F# or C# compiler. To generate documentation model, use one of the overloades of the `Generate` method. </summary>
<namespacedoc><summary>Functionality relating to generating API documentation</summary></namespacedoc>
static member ApiDocs.GenerateHtml: inputs: ApiDocInput list * output: string * collectionName: string * substitutions: FSharp.Formatting.Templating.Substitutions * ?template: string * ?root: string * ?qualify: bool * ?libDirs: string list * ?otherFlags: string list * ?urlRangeHighlight: (System.Uri -> int -> int -> string) * ?onError: (string -> unit) -> ApiDocModel * ApiDocsSearchIndexEntry[]