Skip to content

Commit 07c2cad

Browse files
authored
Merge pull request #1 from urfave/extern-templates
Move templates from string literals to embedded strings
2 parents 18f0005 + 628d08a commit 07c2cad

File tree

6 files changed

+166
-162
lines changed

6 files changed

+166
-162
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.gotmpl text eol=lf

docs.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package docs
22

33
import (
44
"bytes"
5+
_ "embed"
56
"fmt"
67
"io"
78
"os"
@@ -18,6 +19,12 @@ import (
1819
)
1920

2021
var (
22+
//go:embed markdown.md.gotmpl
23+
MarkdownDocTemplate string
24+
25+
//go:embed markdown_tabular.md.gotmpl
26+
MarkdownTabularDocTemplate string
27+
2128
isTracingOn = os.Getenv("URFAVE_CLI_TRACING") == "on"
2229
)
2330

@@ -114,7 +121,7 @@ func ToTabularToFileBetweenTags(cmd *cli.Command, appPath, filePath string, star
114121
return err
115122
}
116123

117-
const comment = "<!-- Documentation inside this block generated by github.com/urfave/cli; DO NOT EDIT -->"
124+
const comment = "<!-- Documentation inside this block generated by github.com/urfave/cli-docs/v3; DO NOT EDIT -->"
118125

119126
// replace content between start and end tags
120127
updated := re.ReplaceAll(content, []byte(strings.Join([]string{start, comment, md, end}, "\n")))

docs_test.go

Lines changed: 54 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package docs
22

33
import (
44
"bytes"
5+
"embed"
56
"io"
67
"io/fs"
78
"net/mail"
@@ -12,14 +13,30 @@ import (
1213
"github.com/urfave/cli/v3"
1314
)
1415

16+
var (
17+
//go:embed testdata
18+
testdata embed.FS
19+
)
20+
1521
func expectFileContent(t *testing.T, file, got string) {
16-
data, err := os.ReadFile(file)
17-
// Ignore windows line endings
18-
data = bytes.ReplaceAll(data, []byte("\r\n"), []byte("\n"))
22+
data, err := testdata.ReadFile(file)
1923

2024
r := require.New(t)
2125
r.NoError(err)
22-
r.Equal(got, string(data))
26+
r.Equal(
27+
string(normalizeNewlines([]byte(got))),
28+
string(normalizeNewlines(data)),
29+
)
30+
}
31+
32+
func normalizeNewlines(d []byte) []byte {
33+
return bytes.ReplaceAll(
34+
bytes.ReplaceAll(
35+
d,
36+
[]byte("\r\n"), []byte("\n"),
37+
),
38+
[]byte("\r"), []byte("\n"),
39+
)
2340
}
2441

2542
func buildExtendedTestCommand() *cli.Command {
@@ -137,13 +154,8 @@ Should be a part of the same code block
137154
}
138155

139156
func TestToMarkdownFull(t *testing.T) {
140-
// Given
141157
cmd := buildExtendedTestCommand()
142-
143-
// When
144158
res, err := ToMarkdown(cmd)
145-
146-
// Then
147159
require.NoError(t, err)
148160
expectFileContent(t, "testdata/expected-doc-full.md", res)
149161
}
@@ -152,28 +164,19 @@ func TestToTabularMarkdown(t *testing.T) {
152164
app := buildExtendedTestCommand()
153165

154166
t.Run("full", func(t *testing.T) {
155-
// When
156167
res, err := ToTabularMarkdown(app, "app")
157-
158-
// Then
159168
require.NoError(t, err)
160169
expectFileContent(t, "testdata/expected-tabular-markdown-full.md", res)
161170
})
162171

163172
t.Run("with empty path", func(t *testing.T) {
164-
// When
165173
res, err := ToTabularMarkdown(app, "")
166-
167-
// Then
168174
require.NoError(t, err)
169175
expectFileContent(t, "testdata/expected-tabular-markdown-full.md", res)
170176
})
171177

172178
t.Run("with custom app path", func(t *testing.T) {
173-
// When
174179
res, err := ToTabularMarkdown(app, "/usr/local/bin")
175-
176-
// Then
177180
require.NoError(t, err)
178181
expectFileContent(t, "testdata/expected-tabular-markdown-custom-app-path.md", res)
179182
})
@@ -183,7 +186,7 @@ func TestToTabularMarkdownFailed(t *testing.T) {
183186
tpl := MarkdownTabularDocTemplate
184187
t.Cleanup(func() { MarkdownTabularDocTemplate = tpl })
185188

186-
MarkdownTabularDocTemplate = "{{ .Foo }}" // invalid template
189+
MarkdownTabularDocTemplate = "{{ .Foo }}"
187190

188191
app := buildExtendedTestCommand()
189192

@@ -196,17 +199,11 @@ func TestToTabularMarkdownFailed(t *testing.T) {
196199
}
197200

198201
func TestToTabularToFileBetweenTags(t *testing.T) {
199-
expectedDocs, fErr := os.ReadFile("testdata/expected-tabular-markdown-full.md")
202+
expectedDocs, fErr := testdata.ReadFile("testdata/expected-tabular-markdown-full.md")
200203

201204
r := require.New(t)
202205
r.NoError(fErr)
203206

204-
// normalizes \r\n (windows) and \r (mac) into \n (unix) (required for tests to pass on windows)
205-
normalizeNewlines := func(d []byte) []byte {
206-
d = bytes.ReplaceAll(d, []byte{13, 10}, []byte{10}) // replace CR LF \r\n (windows) with LF \n (unix)
207-
return bytes.ReplaceAll(d, []byte{13}, []byte{10}) // replace CF \r (mac) with LF \n (unix)
208-
}
209-
210207
t.Run("default tags", func(t *testing.T) {
211208
tmpFile, err := os.CreateTemp("", "")
212209

@@ -238,7 +235,7 @@ Some other text`)
238235
Some description
239236
240237
<!--GENERATED:CLI_DOCS-->
241-
<!-- Documentation inside this block generated by github.com/urfave/cli; DO NOT EDIT -->
238+
<!-- Documentation inside this block generated by github.com/urfave/cli-docs/v3; DO NOT EDIT -->
242239
` + string(expectedDocs) + `
243240
<!--/GENERATED:CLI_DOCS-->
244241
@@ -278,7 +275,7 @@ Some other text`)
278275
Some description
279276
280277
foo_BAR|baz
281-
<!-- Documentation inside this block generated by github.com/urfave/cli; DO NOT EDIT -->
278+
<!-- Documentation inside this block generated by github.com/urfave/cli-docs/v3; DO NOT EDIT -->
282279
` + string(expectedDocs) + `
283280
lorem+ipsum
284281
@@ -302,44 +299,46 @@ Some other text`))
302299
})
303300
}
304301

305-
func TestToMarkdownNoFlags(t *testing.T) {
306-
app := buildExtendedTestCommand()
307-
app.Flags = nil
302+
func TestToMarkdown(t *testing.T) {
303+
t.Run("no flags", func(t *testing.T) {
304+
app := buildExtendedTestCommand()
305+
app.Flags = nil
308306

309-
res, err := ToMarkdown(app)
307+
res, err := ToMarkdown(app)
310308

311-
require.NoError(t, err)
312-
expectFileContent(t, "testdata/expected-doc-no-flags.md", res)
313-
}
309+
require.NoError(t, err)
310+
expectFileContent(t, "testdata/expected-doc-no-flags.md", res)
311+
})
314312

315-
func TestToMarkdownNoCommands(t *testing.T) {
316-
app := buildExtendedTestCommand()
317-
app.Commands = nil
313+
t.Run("no commands", func(t *testing.T) {
314+
app := buildExtendedTestCommand()
315+
app.Commands = nil
318316

319-
res, err := ToMarkdown(app)
317+
res, err := ToMarkdown(app)
320318

321-
require.NoError(t, err)
322-
expectFileContent(t, "testdata/expected-doc-no-commands.md", res)
323-
}
319+
require.NoError(t, err)
320+
expectFileContent(t, "testdata/expected-doc-no-commands.md", res)
321+
})
324322

325-
func TestToMarkdownNoAuthors(t *testing.T) {
326-
app := buildExtendedTestCommand()
327-
app.Authors = []any{}
323+
t.Run("no authors", func(t *testing.T) {
324+
app := buildExtendedTestCommand()
325+
app.Authors = []any{}
328326

329-
res, err := ToMarkdown(app)
327+
res, err := ToMarkdown(app)
330328

331-
require.NoError(t, err)
332-
expectFileContent(t, "testdata/expected-doc-no-authors.md", res)
333-
}
329+
require.NoError(t, err)
330+
expectFileContent(t, "testdata/expected-doc-no-authors.md", res)
331+
})
334332

335-
func TestToMarkdownNoUsageText(t *testing.T) {
336-
app := buildExtendedTestCommand()
337-
app.UsageText = ""
333+
t.Run("no usage text", func(t *testing.T) {
334+
app := buildExtendedTestCommand()
335+
app.UsageText = ""
338336

339-
res, err := ToMarkdown(app)
337+
res, err := ToMarkdown(app)
340338

341-
require.NoError(t, err)
342-
expectFileContent(t, "testdata/expected-doc-no-usagetext.md", res)
339+
require.NoError(t, err)
340+
expectFileContent(t, "testdata/expected-doc-no-usagetext.md", res)
341+
})
343342
}
344343

345344
func TestToMan(t *testing.T) {

markdown.md.gotmpl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{{if gt .SectionNum 0}}% {{ .Command.Name }} {{ .SectionNum }}
2+
3+
{{end}}# NAME
4+
5+
{{ .Command.Name }}{{ if .Command.Usage }} - {{ .Command.Usage }}{{ end }}
6+
7+
# SYNOPSIS
8+
9+
{{ .Command.Name }}
10+
{{ if .SynopsisArgs }}
11+
```
12+
{{ range $v := .SynopsisArgs }}{{ $v }}{{ end }}```
13+
{{ end }}{{ if .Command.Description }}
14+
# DESCRIPTION
15+
16+
{{ .Command.Description }}
17+
{{ end }}
18+
**Usage**:
19+
20+
```{{ if .Command.UsageText }}
21+
{{ .Command.UsageText }}
22+
{{ else }}
23+
{{ .Command.Name }} [GLOBAL OPTIONS] [command [COMMAND OPTIONS]] [ARGUMENTS...]
24+
{{ end }}```
25+
{{ if .GlobalArgs }}
26+
# GLOBAL OPTIONS
27+
{{ range $v := .GlobalArgs }}
28+
{{ $v }}{{ end }}
29+
{{ end }}{{ if .Commands }}
30+
# COMMANDS
31+
{{ range $v := .Commands }}
32+
{{ $v }}{{ end }}{{ end -}}

markdown_tabular.md.gotmpl

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
{{ define "flags" }}
2+
| Name | Description | Default value | Environment variables |
3+
|------|-------------|:-------------:|:---------------------:|
4+
{{ range $flag := . -}}
5+
{{- /**/ -}} | `{{ $flag.Name }}{{ if $flag.TakesValue }}="…"{{ end }}` {{ if $flag.Aliases }}(`{{ join $flag.Aliases "`, `" }}`) {{ end }}
6+
{{- /**/ -}} | {{ $flag.Usage }}
7+
{{- /**/ -}} | {{ if $flag.Default }}`{{ $flag.Default }}`{{ end }}
8+
{{- /**/ -}} | {{ if $flag.EnvVars }}`{{ join $flag.EnvVars "`, `" }}`{{ else }}*none*{{ end }}
9+
{{- /**/ -}} |
10+
{{ end }}
11+
{{ end }}
12+
13+
{{ define "command" }}
14+
### `{{ .Name }}` {{ if gt .Level 0 }}sub{{ end }}command{{ if .Aliases }} (aliases: `{{ join .Aliases "`, `" }}`){{ end }}
15+
{{ if .Usage }}
16+
{{ .Usage }}.
17+
{{ end }}
18+
{{ if .UsageText }}
19+
{{ range $line := .UsageText -}}
20+
> {{ $line }}
21+
{{ end -}}
22+
{{ end }}
23+
{{ if .Description }}
24+
{{ .Description }}.
25+
{{ end }}
26+
Usage:
27+
28+
```bash
29+
$ {{ .AppPath }} [GLOBAL FLAGS] {{ .Name }}{{ if .Flags }} [COMMAND FLAGS]{{ end }} {{ if .ArgsUsage }}{{ .ArgsUsage }}{{ else }}[ARGUMENTS...]{{ end }}
30+
```
31+
32+
{{ if .Flags -}}
33+
The following flags are supported:
34+
{{ template "flags" .Flags }}
35+
{{ end -}}
36+
37+
{{ if .SubCommands -}}
38+
{{ range $subCmd := .SubCommands -}}
39+
{{ template "command" $subCmd }}
40+
{{ end -}}
41+
{{ end -}}
42+
{{ end }}
43+
44+
## CLI interface{{ if .Name }} - {{ .Name }}{{ end }}
45+
46+
{{ if .Description }}{{ .Description }}.
47+
{{ end }}
48+
{{ if .Usage }}{{ .Usage }}.
49+
{{ end }}
50+
{{ if .UsageText }}
51+
{{ range $line := .UsageText -}}
52+
> {{ $line }}
53+
{{ end -}}
54+
{{ end }}
55+
Usage:
56+
57+
```bash
58+
$ {{ .AppPath }}{{ if .GlobalFlags }} [GLOBAL FLAGS]{{ end }} [COMMAND] [COMMAND FLAGS] {{ if .ArgsUsage }}{{ .ArgsUsage }}{{ else }}[ARGUMENTS...]{{ end }}
59+
```
60+
61+
{{ if .GlobalFlags }}
62+
Global flags:
63+
64+
{{ template "flags" .GlobalFlags }}
65+
66+
{{ end -}}
67+
{{ if .Commands -}}
68+
{{ range $cmd := .Commands -}}
69+
{{ template "command" $cmd }}
70+
{{ end }}
71+
{{- end }}

0 commit comments

Comments
 (0)