Skip to content

Commit 3934dfa

Browse files
committed
instead of ipynb -> md do pynb -> fsx
1 parent 5e688fa commit 3934dfa

File tree

3 files changed

+140
-3
lines changed

3 files changed

+140
-3
lines changed

src/FSharp.Formatting.Literate/Literate.fs

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,45 @@ type Literate private () =
223223
|> Transformations.formatCodeSnippets filePath ctx
224224
|> Transformations.evaluateCodeSnippets ctx
225225

226+
/// <summary>
227+
/// Parse pynb string as literate document
228+
/// </summary>
229+
/// <param name="content"></param>
230+
/// <param name="path">optional file path for debugging purposes</param>
231+
/// <param name="definedSymbols"></param>
232+
/// <param name="references"></param>
233+
/// <param name="parseOptions">Defaults to MarkdownParseOptions.AllowYamlFrontMatter</param>
234+
/// <param name="rootInputFolder"></param>
235+
/// <param name="onError"></param>
236+
static member ParsePynbString
237+
(
238+
content,
239+
?path,
240+
?definedSymbols,
241+
?references,
242+
?parseOptions,
243+
?rootInputFolder,
244+
?onError
245+
) =
246+
let onError = defaultArg onError ignore
247+
let ctx = parsingContext None None definedSymbols onError
248+
249+
let filePath =
250+
match path with
251+
| Some s -> s
252+
| None ->
253+
match rootInputFolder with
254+
| None -> "C:\\script.fsx"
255+
| Some r -> Path.Combine(r, "script.fsx")
256+
257+
let content = ParsePynb.pynbStringToFsx content
258+
259+
ParseScript(parseOptions, ctx)
260+
.ParseAndCheckScriptFile(filePath, content, rootInputFolder, onError)
261+
|> Transformations.generateReferences references
262+
|> Transformations.formatCodeSnippets filePath ctx
263+
|> Transformations.evaluateCodeSnippets ctx
264+
226265
// ------------------------------------------------------------------------------------
227266
// Simple writing functions
228267
// ------------------------------------------------------------------------------------
@@ -542,11 +581,11 @@ type Literate private () =
542581
//||| MarkdownParseOptions.ParseNonCodeAsOther
543582
| _ -> parseOptions
544583

545-
let md = ParsePynb.pynbToMarkdown input
584+
let fsx = ParsePynb.pynbToFsx input
546585

547586
let doc =
548-
Literate.ParseMarkdownString(
549-
md,
587+
Literate.ParseScriptString(
588+
fsx,
550589
?fscOptions = fscOptions,
551590
?references = references,
552591
parseOptions = parseOptions,

src/FSharp.Formatting.Literate/ParsePynb.fs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,19 @@ module internal ParsePynb =
2525
| Some outputs ->
2626
let outputsString = outputs |> String.concat "\n"
2727
sprintf $"{codeBlock}\n{outputsString}"
28+
member this.ToFsx() =
29+
match this with
30+
| Markdown source -> $"(**\n{source}\n*)"
31+
| Code code when code.lang = "fsharp" ->
32+
let codeBlock = addLineEnd code.source
33+
34+
match code.outputs with
35+
| None -> codeBlock
36+
| Some outputs ->
37+
let outputsString = outputs |> String.concat "\n"
38+
sprintf $"{codeBlock}\n(**\n{outputsString}\n*)"
39+
| Code _ ->
40+
$"(**\n{this.ToMarkdown()}\n*)"
2841

2942
module Output =
3043
let (|TextHtml|_|) (x: JsonElement) =
@@ -147,6 +160,17 @@ module internal ParsePynb =
147160
let pynbToMarkdown ipynbFile =
148161
ipynbFile |> File.ReadAllText |> pynbStringToMarkdown
149162

163+
164+
let pynbStringToFsx (ipynb: string) =
165+
let json = JsonDocument.Parse(ipynb)
166+
167+
json.RootElement.GetProperty("cells").EnumerateArray()
168+
|> Seq.map (parseCell >> (fun x -> x.ToFsx()))
169+
|> String.concat "\n"
170+
171+
let pynbToFsx ipynbFile =
172+
ipynbFile |> File.ReadAllText |> pynbStringToFsx
173+
150174
let parseFrontMatter ipynbFile =
151175
let json = JsonDocument.Parse(ipynbFile |> File.ReadAllText)
152176

tests/FSharp.Literate.Tests/LiterateTests.fs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,6 +1467,80 @@ let add a b = a + b
14671467

14681468
(mdOut.Trim()) |> shouldEqual (mdIn.Trim())
14691469

1470+
[<Test>]
1471+
let ``Notebook is converted to script exactly right`` () =
1472+
let doc =
1473+
Literate.ParsePynbString(
1474+
"""
1475+
{
1476+
"cells": [
1477+
{
1478+
"cell_type": "code",
1479+
"metadata": {
1480+
"dotnet_interactive": {
1481+
"language": "fsharp"
1482+
},
1483+
"polyglot_notebook": {
1484+
"kernelName": "fsharp"
1485+
}
1486+
},
1487+
"execution_count": null, "outputs": [],
1488+
"source": [
1489+
"let hello = 1\n",
1490+
"\n",
1491+
"let goodbye = 2\n"
1492+
]
1493+
}
1494+
],
1495+
"metadata": {
1496+
"kernelspec": {
1497+
"display_name": ".NET (F#)",
1498+
"language": "F#",
1499+
"name": ".net-fsharp"
1500+
},
1501+
"language_info": {
1502+
"file_extension": ".fs",
1503+
"mimetype": "text/x-fsharp",
1504+
"name": "polyglot-notebook",
1505+
"pygments_lexer": "fsharp"
1506+
},
1507+
"polyglot_notebook": {
1508+
"kernelInfo": {
1509+
"defaultKernelName": "fsharp",
1510+
"items": [
1511+
{
1512+
"aliases": [],
1513+
"languageName": "fsharp",
1514+
"name": "fsharp"
1515+
}
1516+
]
1517+
}
1518+
}
1519+
},
1520+
"nbformat": 4,
1521+
"nbformat_minor": 2
1522+
}""",
1523+
parseOptions =
1524+
(MarkdownParseOptions.ParseCodeAsOther
1525+
||| MarkdownParseOptions.ParseNonCodeAsOther)
1526+
)
1527+
1528+
let fsx = Literate.ToFsx(doc)
1529+
printfn "----"
1530+
printfn "%s" fsx
1531+
printfn "----"
1532+
1533+
let fsx2 = fsx.Replace("\r\n", "\n").Replace("\n", "!")
1534+
1535+
let expected =
1536+
"""let hello = 1
1537+
1538+
let goodbye = 2"""
1539+
1540+
let expected2 = expected.Replace("\r\n", "\n").Replace("\n", "!")
1541+
1542+
fsx2 |> shouldEqual expected2
1543+
14701544
[<Test>]
14711545
let ``Script output is exactly right`` () =
14721546
let md =

0 commit comments

Comments
 (0)