Skip to content

Commit

Permalink
Merge pull request #10 from miniscruff/8-support-dotenv
Browse files Browse the repository at this point in the history
Support dotenv output format
  • Loading branch information
g4s8 committed Feb 23, 2024
2 parents 2c49c74 + ff12c2c commit 988bb32
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 6 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ type Config struct {
* `-type`: Specify the target struct type name to generate documentation for.
If ommited, the next type after `go:generate` comment will be used.
* `-format` (default: `markdown`) - Set output format type, either `markdown`,
`plaintext` or `html`.
`plaintext`, `html`, or `dotenv`.
* `-all` - Generate documentation for all types in the file.
* `-env-prefix` - Environment variable prefix.
* `-no-styles` - Disable built-int CSS styles for HTML format.
Expand Down
53 changes: 53 additions & 0 deletions _examples/complex.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Environment Variables


## ComplexConfig
## ComplexConfig is an example configuration structure.
## It contains a few fields with different types of tags.
## It is trying to cover all the possible cases.
#
## Secret is a secret value that is read from a file.
## (from-file)
# SECRET=""
## Password is a password that is read from a file.
## (from-file, default: '/tmp/password')
# PASSWORD="/tmp/password"
## Certificate is a certificate that is read from a file.
## (expand, from-file, default: '${CERTIFICATE_FILE}')
# CERTIFICATE="${CERTIFICATE_FILE}"
## Key is a secret key.
## (required)
# SECRET_KEY=""
## SecretVal is a secret value.
## (required, non-empty)
# SECRET_VAL=""
## Hosts is a list of hosts.
## (separated by ':', required)
# HOSTS=""
## Words is just a list of words.
## (comma-separated, from-file, default: 'one,two,three')
# WORDS="one,two,three"
## Just a comment.
## (required, default: 'This is a comment.')
# COMMENT="This is a comment."
#
## Anon is an anonymous structure.
#
## User is a user name.
## (required)
# ANON_USER=""
## Pass is a password.
## (required)
# ANON_PASS=""

## NextConfig
#
## Mount is a mount point.
## (required)
# MOUNT=""

## FieldNames
## FieldNames uses field names as env names.
#
## Quux is a field with a tag.
# QUUX=""
3 changes: 2 additions & 1 deletion _examples/complex.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ package main
//go:generate go run ../ -output complex.txt -all -format plaintext
//go:generate go run ../ -output x_complex.md -all -env-prefix X_
//go:generate go run ../ -output complex-nostyle.html -format html -all -no-styles
//go:generate go run ../ -output complex.env -all -format dotenv
type ComplexConfig struct {
// Secret is a secret value that is read from a file.
Secret string `env:"SECRET,file"`
// Password is a password that is read from a file.
Password string `env:"PASSWORD,file" envDefault:"/tmp/password" json:"password"`
Password string `env:"PASSWORD,file" envDefault:"/tmp/password" json:"password"`
// Certificate is a certificate that is read from a file.
Certificate string `env:"CERTIFICATE,file,expand" envDefault:"${CERTIFICATE_FILE}"`
// Key is a secret key.
Expand Down
17 changes: 17 additions & 0 deletions _examples/config.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Environment Variables


## Config
## Config is an example configuration structure.
## It is used to generate documentation for the configuration
## using the commands below.
#
## Hosts name of hosts to listen on.
## (separated by ';', required)
# HOST=""
## Port to listen on.
## (required, non-empty)
# PORT=""
## Debug mode enabled.
## (default: 'false')
# DEBUG="false"
1 change: 1 addition & 0 deletions _examples/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package main
//go:generate go run ../ -output config.txt -format plaintext
//go:generate go run ../ -output config.md -format markdown
//go:generate go run ../ -output config.html -format html
//go:generate go run ../ -output config.env -format dotenv
type Config struct {
// Hosts name of hosts to listen on.
Hosts []string `env:"HOST,required", envSeparator:";"`
Expand Down
41 changes: 41 additions & 0 deletions _examples/envprefix.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Environment Variables


## Settings
## Settings is the application settings.
#
#
## Database is the database settings.
#
## Port is the port to connect to
## (required)
# DB_PORT=""
## Host is the host to connect to
## (required, non-empty, default: 'localhost')
# DB_HOST="localhost"
## User is the user to connect as
# DB_USER=""
## Password is the password to use
# DB_PASSWORD=""
## DisableTLS is the flag to disable TLS
# DB_DISABLE_TLS=""
#
## ServerConfig is the server settings.
#
## Port is the port to listen on
## (required)
# SERVER_PORT=""
## Host is the host to listen on
## (required, non-empty, default: 'localhost')
# SERVER_HOST="localhost"
#
## TimeoutConfig is the timeout settings.
#
## Read is the read timeout
## (default: '30')
# SERVER_TIMEOUT_READ="30"
## Write is the write timeout
## (default: '30')
# SERVER_TIMEOUT_WRITE="30"
## Debug is the debug flag
# DEBUG=""
1 change: 1 addition & 0 deletions _examples/envprefix.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package main
//go:generate go run ../ -output envprefix.txt -format plaintext -type Settings
//go:generate go run ../ -output envprefix.md -type Settings
//go:generate go run ../ -output envprefix.html -format html -type Settings
//go:generate go run ../ -output envprefix.env -format dotenv -type Settings
type Settings struct {
// Database is the database settings
Database Database `envPrefix:"DB_"`
Expand Down
2 changes: 2 additions & 0 deletions generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ func withFormat(formatName string) generatorOption {
g.tmpl = tmplPlaintext
case "html":
g.tmpl = tmplHTML
case "dotenv":
g.tmpl = tmplDotEnv
default:
return fmt.Errorf("unknown format: %s", formatName)
}
Expand Down
1 change: 1 addition & 0 deletions generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ func TestOptions(t *testing.T) {
{name: "markdown", expect: tmplMarkdown},
{name: "html", expect: tmplHTML},
{name: "plaintext", expect: tmplPlaintext},
{name: "dotenv", expect: tmplDotEnv},
{name: "unknown", expectErr: true},
} {
t.Run(c.name, func(t *testing.T) {
Expand Down
13 changes: 9 additions & 4 deletions render.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,21 @@ var templates embed.FS

var tplFuncs = map[string]any{
"repeat": strings.Repeat,
}

func _() {
// texttmpl.ParseFS
"split": strings.Split,
"strAppend": func(arr []string, item string) []string {
return append(arr, item)
},
"join": strings.Join,
"strSlice": func() []string {
return make([]string, 0)
},
}

var (
tmplMarkdown = texttmpl.Must(texttmpl.New("markdown.tmpl").Funcs(tplFuncs).ParseFS(templates, "templ/markdown.tmpl"))
tmplHTML = htmltmpl.Must(htmltmpl.New("html.tmpl").Funcs(tplFuncs).ParseFS(templates, "templ/html.tmpl"))
tmplPlaintext = texttmpl.Must(texttmpl.New("plaintext.tmpl").Funcs(tplFuncs).ParseFS(templates, "templ/plaintext.tmpl"))
tmplDotEnv = texttmpl.Must(texttmpl.New("dotenv.tmpl").Funcs(tplFuncs).ParseFS(templates, "templ/dotenv.tmpl"))
)

type template interface {
Expand Down
72 changes: 72 additions & 0 deletions templ/dotenv.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{{/*
Render doc lines: split doc by newline and prefix with `##` each line.
*/}}
{{- define "doc.lines" }}
{{- if . }}
{{- $docLines := split . "\n" }}
{{- range $line := $docLines }}
## {{ $line }}
{{- end }}
{{- end }}
{{- end -}}

{{- define "item" }}
{{- if eq .EnvName "" }}
#
{{- end }}
{{- template "doc.lines" .Doc }}
{{- if .EnvName }}
{{- if .Doc }}
{{- printf "\n" }}
{{- end }}
{{- $opts := strSlice }}
{{- if eq .EnvSeparator "," }}
{{- $opts = (strAppend $opts "comma-separated") }}
{{- else if ne .EnvSeparator "" }}
{{- $opts = (printf "separated by '%s'" .EnvSeparator | strAppend $opts) }}
{{- end }}
{{- if .Required }}
{{- $opts = (strAppend $opts "required") }}
{{- end }}
{{- if .Expand }}
{{- $opts = (strAppend $opts "expand") }}
{{- end }}
{{- if .NonEmpty }}
{{- $opts = (strAppend $opts "non-empty") }}
{{- end }}
{{- if .FromFile }}
{{- $opts = (strAppend $opts "from-file") }}
{{- end }}
{{- if ne .EnvDefault "" }}
{{- $opts = (printf "default: '%s'" .EnvDefault | strAppend $opts) }}
{{- end }}
{{- if $opts }}
{{- join $opts ", " | printf "## (%s)\n" }}
{{- end }}
{{- if .EnvDefault }}
{{- printf `# %s="%s"` .EnvName .EnvDefault }}
{{- else }}
{{- printf `# %s=""` .EnvName }}
{{- end }}
{{- end }}
{{- $children := .Children 0 }}
{{- if $children }}
#
{{- range $child := $children }}
{{- template "item" $child }}
{{- end }}
{{- end }}
{{- end -}}

# {{ .Title }}
{{ range .Sections }}
{{- print "\n" }}
{{- if .Name }}
## {{ .Name }}
{{- end }}
{{- template "doc.lines" .Doc }}
#
{{- range $item := .Items }}
{{- template "item" $item }}
{{- end }}
{{- end -}}

0 comments on commit 988bb32

Please sign in to comment.