Skip to content

Commit

Permalink
Add support for Markdown rendering (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
unguiculus committed Nov 22, 2021
1 parent 91c7278 commit b15937a
Show file tree
Hide file tree
Showing 15 changed files with 432 additions and 38 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
out.asciidoc
out.md
.idea
27 changes: 22 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,34 @@ Pre-built Linux binaries can be downloaded from the Github Releases tab. Alterna
go get -u github.com/elastic/crd-ref-docs
```

The tool can be invoked as follows to generate documentation in Asciidoc format:
The tool can be invoked as follows to generate documentation:

```
crd-ref-docs \
--source-path=$GOPATH/src/github.com/elastic/cloud-on-k8s/pkg/apis \
--config=config.yaml
```

By default, documentation is rendered in Asciidoc format.
In order to generate documentation in Markdown format, you will have to specify the `markdown` renderer:

```
crd-ref-docs \
--source-path=$GOPATH/src/github.com/elastic/cloud-on-k8s/pkg/apis \
--config=config.yaml \
--renderer=asciidoctor \
--templates-dir=templates/asciidoctor \
--output-path=out.asciidoc
--renderer=markdown
```

Default templates are embedded in the binary.
You may provide your own templates by specifying the templates directory:

```
crd-ref-docs \
--source-path=$GOPATH/src/github.com/elastic/cloud-on-k8s/pkg/apis \
--config=config.yaml \
--renderer=asciidoctor \
--templates-dir=templates/asciidoctor
```

### Configuration

Expand All @@ -50,5 +67,5 @@ processor:

render:
# Version of Kubernetes to use when generating links to Kubernetes API documentation.
kubernetesVersion: 1.15
kubernetesVersion: 1.22
```
2 changes: 1 addition & 1 deletion config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ processor:
- "TypeMeta$"

render:
kubernetesVersion: 1.15
kubernetesVersion: 1.22
4 changes: 2 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ func main() {
cmd.Flags().StringVar(&args.Config, "config", "config.yaml", "Path to config file")
cmd.Flags().StringVar(&args.SourcePath, "source-path", "", "Path to source directory containing CRDs")
cmd.Flags().StringVar(&args.TemplatesDir, "templates-dir", "", "Path to the directory containing template files")
cmd.Flags().StringVar(&args.Renderer, "renderer", "asciidoctor", "Renderer to use")
cmd.Flags().StringVar(&args.OutputPath, "output-path", "out.asciidoc", "Path to output the rendered result")
cmd.Flags().StringVar(&args.Renderer, "renderer", "asciidoctor", "Renderer to use ('asciidoctor' or 'markdown')")
cmd.Flags().StringVar(&args.OutputPath, "output-path", ".", "Path to output the rendered result")
cmd.Flags().IntVar(&args.MaxDepth, "max-depth", 6, "Maximum recursion level for type discovery")

cmd.Execute()
Expand Down
16 changes: 1 addition & 15 deletions renderer/asciidoctor.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
"text/template"

Expand Down Expand Up @@ -66,20 +65,7 @@ func (adr *AsciidoctorRenderer) Render(gvd []types.GroupVersionDetails) error {
return err
}

outputFile := adr.conf.OutputPath
finfo, err := os.Stat(outputFile)
if err != nil && !os.IsNotExist(err) {
return err
}

if finfo != nil && finfo.IsDir() {
outputFile = filepath.Join(outputFile, "out.asciidoc")
}

f, err := os.Create(outputFile)
if err != nil {
return err
}
f, err := createOutFile(adr.conf.OutputPath, "out.asciidoc")
defer f.Close()

return tmpl.ExecuteTemplate(f, mainTemplate, gvd)
Expand Down
142 changes: 142 additions & 0 deletions renderer/markdown.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package renderer

import (
"fmt"
"io/fs"
"os"
"strings"
"text/template"

"github.com/Masterminds/sprig"
"github.com/elastic/crd-ref-docs/config"
"github.com/elastic/crd-ref-docs/templates"
"github.com/elastic/crd-ref-docs/types"
)

type MarkdownRenderer struct {
conf *config.Config
*Functions
}

func NewMarkdownRenderer(conf *config.Config) (*MarkdownRenderer, error) {
baseFuncs, err := NewFunctions(conf)
if err != nil {
return nil, err
}
return &MarkdownRenderer{conf: conf, Functions: baseFuncs}, nil
}

func (m *MarkdownRenderer) Render(gvd []types.GroupVersionDetails) error {
funcMap := combinedFuncMap(funcMap{prefix: "markdown", funcs: m.ToFuncMap()}, funcMap{funcs: sprig.TxtFuncMap()})

var tpls fs.FS
if m.conf.TemplatesDir != "" {
tpls = os.DirFS(m.conf.TemplatesDir)
} else {
sub, err := fs.Sub(templates.Root, "markdown")
if err != nil {
return err
}
tpls = sub
}

tmpl, err := loadTemplate(tpls, funcMap)
if err != nil {
return err
}

f, err := createOutFile(m.conf.OutputPath, "out.md")
defer f.Close()

return tmpl.ExecuteTemplate(f, mainTemplate, gvd)
}

func (m *MarkdownRenderer) ToFuncMap() template.FuncMap {
return template.FuncMap{
"GroupVersionID": m.GroupVersionID,
"RenderExternalLink": m.RenderExternalLink,
"RenderGVLink": m.RenderGVLink,
"RenderLocalLink": m.RenderLocalLink,
"RenderType": m.RenderType,
"RenderTypeLink": m.RenderTypeLink,
"SafeID": m.SafeID,
"ShouldRenderType": m.ShouldRenderType,
"TypeID": m.TypeID,
}
}

func (m *MarkdownRenderer) ShouldRenderType(t *types.Type) bool {
return t != nil && (t.GVK != nil || len(t.References) > 0)
}

func (m *MarkdownRenderer) RenderType(t *types.Type) string {
var sb strings.Builder
switch t.Kind {
case types.MapKind:
sb.WriteString("object (")
sb.WriteString("keys:")
sb.WriteString(m.RenderTypeLink(t.KeyType))
sb.WriteString(", values:")
sb.WriteString(m.RenderTypeLink(t.ValueType))
sb.WriteString(")")
case types.ArrayKind, types.SliceKind:
sb.WriteString(m.RenderTypeLink(t.UnderlyingType))
sb.WriteString(" array")
default:
sb.WriteString(m.RenderTypeLink(t))
}

return sb.String()
}

func (m *MarkdownRenderer) RenderTypeLink(t *types.Type) string {
text := m.SimplifiedTypeName(t)

link, local := m.LinkForType(t)
if link == "" {
return text
}

if local {
return m.RenderLocalLink(text)
} else {
return m.RenderExternalLink(link, text)
}
}

func (m *MarkdownRenderer) RenderLocalLink(text string) string {
anchor := strings.ToLower(
strings.NewReplacer(
" ", "-",
".", "",
"/", "",
"(", "",
")", "",
).Replace(text),
)
return fmt.Sprintf("[%s](#%s)", text, anchor)
}

func (m *MarkdownRenderer) RenderExternalLink(link, text string) string {
return fmt.Sprintf("[%s](%s)", text, link)
}

func (m *MarkdownRenderer) RenderGVLink(gv types.GroupVersionDetails) string {
return m.RenderLocalLink(gv.GroupVersionString())
}
17 changes: 17 additions & 0 deletions renderer/renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package renderer
import (
"fmt"
"io/fs"
"os"
"path/filepath"
"text/template"

"github.com/elastic/crd-ref-docs/config"
Expand All @@ -35,6 +37,8 @@ func New(conf *config.Config) (Renderer, error) {
switch conf.Renderer {
case "asciidoctor":
return NewAsciidoctorRenderer(conf)
case "markdown":
return NewMarkdownRenderer(conf)
default:
return nil, fmt.Errorf("unknown renderer: %s", conf.Renderer)
}
Expand All @@ -59,3 +63,16 @@ func combinedFuncMap(funcs ...funcMap) template.FuncMap {

return m
}

func createOutFile(outputPath string, defaultFileName string) (*os.File, error) {
finfo, err := os.Stat(outputPath)
if err != nil && !os.IsNotExist(err) {
return nil, err
}

if finfo != nil && finfo.IsDir() {
outputPath = filepath.Join(outputPath, defaultFileName)
}

return os.Create(outputPath)
}
19 changes: 19 additions & 0 deletions templates/markdown/gv_details.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{{- define "gvDetails" -}}
{{- $gv := . -}}

## {{ $gv.GroupVersionString }}

{{ $gv.Doc }}

{{- if $gv.Kinds }}
### Resource Types
{{- range $gv.SortedKinds }}
- {{ $gv.TypeForKind . | markdownRenderTypeLink }}
{{- end }}
{{ end }}

{{ range $gv.SortedTypes }}
{{ template "type" . }}
{{ end }}

{{- end -}}
15 changes: 15 additions & 0 deletions templates/markdown/gv_list.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{{- define "gvList" -}}
{{- $groupVersions := . -}}

# API Reference

## Packages
{{- range $groupVersions }}
- {{ markdownRenderGVLink . }}
{{- end }}

{{ range $groupVersions }}
{{ template "gvDetails" . }}
{{ end }}

{{- end -}}
33 changes: 33 additions & 0 deletions templates/markdown/type.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{{- define "type" -}}
{{- $type := . -}}
{{- if markdownShouldRenderType $type -}}

#### {{ $type.Name }}

{{ if $type.IsAlias }}_Underlying type:_ `{{ markdownRenderTypeLink $type.UnderlyingType }}`{{ end }}

{{ $type.Doc }}

{{ if $type.References -}}
_Appears in:_
{{- range $type.SortedReferences }}
- {{ markdownRenderTypeLink . }}
{{- end }}
{{- end }}

{{ if $type.Members -}}
| Field | Description |
| --- | --- |
{{ if $type.GVK -}}
| `apiVersion` _string_ | `{{ $type.GVK.Group }}/{{ $type.GVK.Version }}`
| `kind` _string_ | `{{ $type.GVK.Kind }}`
{{ end -}}

{{ range $type.Members -}}
| `{{ .Name }}` _{{ markdownRenderType .Type }}_ | {{ template "type_members" . }} |
{{ end -}}

{{ end -}}

{{- end -}}
{{- end -}}
8 changes: 8 additions & 0 deletions templates/markdown/type_members.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{{- define "type_members" -}}
{{- $field := . -}}
{{- if eq $field.Name "metadata" -}}
Refer to Kubernetes API documentation for fields of `metadata`.
{{- else -}}
{{ $field.Doc }}
{{- end -}}
{{- end -}}
1 change: 1 addition & 0 deletions templates/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ package templates
import "embed"

//go:embed asciidoctor
//go:embed markdown
var Root embed.FS
Loading

0 comments on commit b15937a

Please sign in to comment.