Skip to content
Merged
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
7 changes: 7 additions & 0 deletions src/FSharp.Formatting.ApiDocs/GenerateHtml.fs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/// Internal module that generates HTML documentation output from an <see cref="T:FSharp.Formatting.ApiDocs.ApiDocModel"/>.
/// Produces one HTML file per namespace and per entity, plus an index file.
module internal FSharp.Formatting.ApiDocs.GenerateHtml

open System
Expand All @@ -13,13 +15,18 @@ open FSharp.Formatting.HtmlModel.Html
/// Embed some HTML generated in GenerateModel
let embed (x: ApiDocHtml) = !!x.HtmlText

/// Wraps the HTML text of an <see cref="T:FSharp.Formatting.ApiDocs.ApiDocHtml"/> in a summary paragraph,
/// unless the content starts with a <c>&lt;pre&gt;</c> tag (which cannot be nested inside <c>&lt;p&gt;</c>).
let fsdocsSummary (x: ApiDocHtml) =
// the <pre> tag is not allowed inside a <p> tag.
if x.HtmlText.StartsWith("<pre>", StringComparison.Ordinal) then
embed x
else
div [ Class "fsdocs-summary-contents" ] [ p [ Class "fsdocs-summary" ] [ embed x ] ]

/// Renders HTML API documentation for all namespaces and entities in an
/// <see cref="T:FSharp.Formatting.ApiDocs.ApiDocModel"/>. Writes one file per namespace
/// and per entity to the output directory using the supplied template.
type HtmlRender(model: ApiDocModel, ?menuTemplateFolder: string) =
let root = model.Root
let collectionName = model.Collection.CollectionName
Expand Down
5 changes: 5 additions & 0 deletions src/FSharp.Formatting.CodeFormat/Pervasive.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ open FSharp.Compiler.Text
[<assembly: InternalsVisibleTo("FSharp.CodeFormat.Tests")>]
do ()

/// Computation expression builder for <c>Async&lt;'T option&gt;</c> workflows,
/// enabling monadic short-circuiting on <c>None</c>.
[<Sealed>]
type AsyncMaybeBuilder() =

Expand Down Expand Up @@ -93,16 +95,19 @@ type AsyncMaybeBuilder() =

let asyncMaybe = AsyncMaybeBuilder()

/// Lifts an <c>Async&lt;'T&gt;</c> into <c>Async&lt;'T option&gt;</c> by wrapping the result in <c>Some</c>.
let inline liftAsync (computation: Async<'T>) : Async<'T option> =
async {
let! a = computation
return Some a
}


/// Additional async combinators used internally in the code-format pipeline.
[<RequireQualifiedAccess>]
module Async =

/// Maps a function over the result of an async workflow.
let map (f: 'T -> 'U) (a: Async<'T>) : Async<'U> =
async {
let! a = a
Expand Down
18 changes: 18 additions & 0 deletions src/FSharp.Formatting.Literate/ParsePynb.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ open System.Text.Json
open FSharp.Formatting.Templating
open FSharp.Formatting.PynbModel

/// Internal module for parsing Jupyter notebook (.ipynb) files into <see cref="T:FSharp.Formatting.Literate.ParsePynb.ParsedCell"/> values
/// that can be converted to Markdown or .fsx for literate processing.
module internal ParsePynb =

/// A single cell from a Jupyter notebook, either a Markdown cell or a code cell.
type ParsedCell =
| Code of
{| lang: string
Expand Down Expand Up @@ -39,7 +42,9 @@ module internal ParsePynb =
sprintf $"%s{codeBlock}\n(**\n%s{outputsString}\n*)"
| Code _ -> $"(**\n%s{this.ToMarkdown()}\n*)"

/// Active patterns for matching Jupyter output cells by MIME type and output type.
module Output =
/// Matches a JSON element that contains <c>text/html</c> output data.
let (|TextHtml|_|) (x: JsonElement) =
match x.TryGetProperty("text/html") with
| true, html ->
Expand All @@ -51,13 +56,15 @@ module internal ParsePynb =
Some $"<p>%s{html}</p>"
| _ -> None

/// Matches a JSON element that contains <c>text/plain</c> output data.
let (|TextPlain|_|) (x: JsonElement) =
match x.TryGetProperty("text/plain") with
| true, text ->
let text = text.EnumerateArray() |> Seq.map (fun x -> x.GetString()) |> String.concat ""
Some $"""<table class="pre"><tbody><tr><td><pre><code>%s{text}</code></pre></td></tr></tbody></table>"""
| _ -> None

/// Matches a display-data output cell and returns its rendered HTML or plain-text content.
let (|DisplayData|_|) (x: JsonElement) =
match x.TryGetProperty("output_type") with
| true, outputType ->
Expand All @@ -72,6 +79,7 @@ module internal ParsePynb =
None
| _ -> failwith "no output_type property"

/// Matches a stream output cell and returns its text content as an HTML code block.
let (|Stream|_|) (x: JsonElement) =
match x.TryGetProperty("output_type") with
| true, outputType ->
Expand All @@ -87,12 +95,14 @@ module internal ParsePynb =
None
| _ -> failwith "no output_type property"

/// Parses an output JSON element and returns its rendered HTML string.
let parse (output: JsonElement) =
match output with
| Stream stream -> stream
| DisplayData displayData -> displayData
| s -> failwith $"""unknown output %s{s.GetProperty("output_type").GetString()}"""

/// Returns the concatenated source lines of a notebook cell as a single string.
let getSource (cell: JsonElement) =
let source =
match cell.TryGetProperty("source") with
Expand All @@ -101,6 +111,7 @@ module internal ParsePynb =

source |> Seq.map (fun x -> x.GetString()) |> String.concat ""

/// Returns the rendered output strings from a code cell, or <c>None</c> if there are no outputs.
let collectOutputs (cell: JsonElement) =
match cell.TryGetProperty("outputs") with
| true, outputs ->
Expand All @@ -112,6 +123,7 @@ module internal ParsePynb =
xs |> Seq.map Output.parse |> Seq.toArray |> Some
| _ -> None

/// Parses a polyglot code cell, extracting the kernel name, source, and rendered outputs.
let getCode (cell: JsonElement) =
let lang =
let metadata (elem: JsonElement) =
Expand Down Expand Up @@ -140,6 +152,7 @@ module internal ParsePynb =
outputs = outputs |}


/// Parses a single notebook cell JSON element into a <see cref="T:FSharp.Formatting.Literate.ParsePynb.ParsedCell"/>.
let parseCell (cell: JsonElement) =
let cell_type =
match cell.TryGetProperty("cell_type") with
Expand All @@ -154,27 +167,32 @@ module internal ParsePynb =
| "code" -> getCode cell
| _ -> failwith $"unknown cell type %s{cell_type}"

/// Converts a Jupyter notebook JSON string to a Markdown string by serialising each cell.
let pynbStringToMarkdown (ipynb: string) =
let json = JsonDocument.Parse(ipynb)

json.RootElement.GetProperty("cells").EnumerateArray()
|> Seq.map (parseCell >> (fun x -> x.ToMarkdown()))
|> String.concat "\n"

/// Reads a Jupyter notebook file and converts it to a Markdown string.
let pynbToMarkdown ipynbFile =
ipynbFile |> File.ReadAllText |> pynbStringToMarkdown


/// Converts a Jupyter notebook JSON string to an .fsx script string.
let pynbStringToFsx (ipynb: string) =
let json = JsonDocument.Parse(ipynb)

json.RootElement.GetProperty("cells").EnumerateArray()
|> Seq.map (parseCell >> (fun x -> x.ToFsx()))
|> String.concat "\n"

/// Reads a Jupyter notebook file and converts it to an .fsx script string.
let pynbToFsx ipynbFile =
ipynbFile |> File.ReadAllText |> pynbStringToFsx

/// Reads the front-matter block from a Jupyter notebook file, if present in the first Markdown cell.
let parseFrontMatter ipynbFile =
let json = JsonDocument.Parse(ipynbFile |> File.ReadAllText)

Expand Down