Skip to content

Commit 9146fe7

Browse files
Add fsdocs init command to scaffold docs folder (#872)
Adds a new 'fsdocs init' verb that creates a minimal docs/index.md (and optionally _template.html) for new projects. Options: --input <dir> Directory to initialise (default: docs) --force Overwrite existing files --with-template Also scaffold a _template.html Closes #872 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 8e3b463 commit 9146fe7

4 files changed

Lines changed: 100 additions & 1 deletion

File tree

RELEASE_NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## [Unreleased]
44

55
### Added
6+
* Add `fsdocs init` command to scaffold a minimal `docs/index.md` (and optionally `_template.html`) for new projects. [#872](https://github.com/fsprojects/FSharp.Formatting/issues/872)
67
* Add `<FsDocsAllowExecutableProject>true</FsDocsAllowExecutableProject>` project file setting to include executable projects (OutputType=Exe/WinExe) in API documentation generation. [#918](https://github.com/fsprojects/FSharp.Formatting/issues/918)
78
* Add `{{fsdocs-logo-alt}}` substitution (configurable via `<FsDocsLogoAlt>` MSBuild property, defaults to `Logo`) for accessible alt text on the header logo image. [#626](https://github.com/fsprojects/FSharp.Formatting/issues/626)
89

src/fsdocs-tool/InitCommand.fs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
namespace fsdocs
2+
3+
open CommandLine
4+
open System
5+
open System.IO
6+
7+
/// The fsdocs init command: scaffold a minimal docs folder for a new project.
8+
[<Verb("init", HelpText = "initialize a docs folder with a default index.md and optionally a _template.html")>]
9+
type InitCommand() =
10+
11+
[<Option("input", Required = false, Default = "docs", HelpText = "The directory to initialize (default: docs).")>]
12+
member val input = "docs" with get, set
13+
14+
[<Option("force", Required = false, Default = false, HelpText = "Overwrite existing files (default: false).")>]
15+
member val force = false with get, set
16+
17+
[<Option("with-template",
18+
Required = false,
19+
Default = false,
20+
HelpText = "Also scaffold a _template.html file in the docs directory.")>]
21+
member val withTemplate = false with get, set
22+
23+
member this.Execute() =
24+
let docsDir =
25+
if Path.IsPathRooted(this.input) then
26+
this.input
27+
else
28+
Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, this.input))
29+
30+
if not (Directory.Exists(docsDir)) then
31+
printfn "Creating directory: %s" docsDir
32+
Directory.CreateDirectory(docsDir) |> ignore
33+
34+
let indexPath = Path.Combine(docsDir, "index.md")
35+
36+
let writeIfNeeded path content =
37+
if File.Exists(path) && not this.force then
38+
printfn "Skipping %s (already exists; use --force to overwrite)" path
39+
else
40+
printfn "Writing %s" path
41+
File.WriteAllText(path, (content: string))
42+
43+
let indexContent =
44+
"""---
45+
title: Documentation
46+
category: Documentation
47+
categoryindex: 1
48+
index: 1
49+
---
50+
51+
# Your Project Name
52+
53+
Welcome to the documentation for **Your Project Name**.
54+
55+
## Getting Started
56+
57+
Add your documentation here. You can use Markdown, F# scripts (`.fsx`) or Jupyter notebooks (`.ipynb`).
58+
59+
Run `dotnet fsdocs watch` to preview the site locally.
60+
"""
61+
62+
writeIfNeeded indexPath indexContent
63+
64+
if this.withTemplate then
65+
let templatePath = Path.Combine(docsDir, "_template.html")
66+
67+
let templateContent =
68+
"""<!DOCTYPE html>
69+
<html lang="en">
70+
<head>
71+
<meta charset="utf-8">
72+
<title>{{fsdocs-page-title}}</title>
73+
<meta name="viewport" content="width=device-width, initial-scale=1">
74+
<link rel="stylesheet" href="{{root}}content/fsdocs-default.css">
75+
</head>
76+
<body>
77+
<header>
78+
<div class="navbar">
79+
<a href="{{root}}">{{fsdocs-logo-alt}}</a>
80+
</div>
81+
</header>
82+
<div class="container">
83+
<div class="content">
84+
{{fsdocs-content}}
85+
</div>
86+
</div>
87+
<script src="{{root}}content/fsdocs-tips.js"></script>
88+
</body>
89+
</html>
90+
"""
91+
92+
writeIfNeeded templatePath templateContent
93+
94+
printfn ""
95+
printfn "Done! Run 'dotnet fsdocs watch --input %s' to preview your documentation." this.input
96+
0

src/fsdocs-tool/Program.fs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ do ()
88
[<EntryPoint>]
99
let main argv =
1010
CommandLine.Parser.Default
11-
.ParseArguments<BuildCommand, WatchCommand>(argv)
11+
.ParseArguments<BuildCommand, WatchCommand, InitCommand>(argv)
1212
.MapResult(
1313
(fun (opts: BuildCommand) -> opts.Execute()),
1414
(fun (opts: WatchCommand) -> opts.Execute()),
15+
(fun (opts: InitCommand) -> opts.Execute()),
1516
(fun _ -> 1)
1617
)

src/fsdocs-tool/fsdocs-tool.fsproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
<Compile Include="Options.fs" />
2020
<Compile Include="ProjectCracker.fs" />
2121
<Compile Include="BuildCommand.fs" />
22+
<Compile Include="InitCommand.fs" />
2223
<Compile Include="Program.fs" />
2324
</ItemGroup>
2425

0 commit comments

Comments
 (0)