Skip to content

Commit

Permalink
feat: render separate markdown files for each schema def (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
twelvelabs authored Dec 30, 2023
1 parent 1cf627a commit 73d9a66
Show file tree
Hide file tree
Showing 13 changed files with 381 additions and 131 deletions.
5 changes: 1 addition & 4 deletions .markdownlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
# - https://github.com/DavidAnson/markdownlint/blob/main/schema/.markdownlint.yaml

# MD013/line-length - Line length
MD013:
line_length: 120
code_blocks: false
tables: false
MD013: false

# MD033/no-inline-html - Inline HTML
MD033: false
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ lint: ## Lint the app
format: ## Format the app
@bin/format.sh

.PHONY: run
run: ## Run the app
@bin/run.sh

.PHONY: test
test: ## Test the app
@bin/test.sh
Expand Down
7 changes: 7 additions & 0 deletions bin/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -o errexit -o errtrace -o nounset -o pipefail

schemadoc gen --in ./schemas --out ./out -vv
markdownlint --fix out/

echo "[run] ✅"
3 changes: 3 additions & 0 deletions cspell.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ ignorePaths:
- go.mod
- go.sum
- "**/testdata/**"
- schemas/
ignoreRegExpList:
- /import \([^)]+\)/g
language: en
Expand Down Expand Up @@ -52,6 +53,7 @@ words:
- goldmark
- gomod
- goreleaser
- gosec
- gpgconf
- gpgsign
- hadolint
Expand All @@ -76,6 +78,7 @@ words:
- signingkey
- sigstore
- simplejson
- stripmd
- tablewriter
- trimpath
- twelvelabs
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ require (
github.com/stretchr/testify v1.8.4
github.com/tdewolff/minify/v2 v2.20.10
github.com/twelvelabs/termite v0.13.1
github.com/writeas/go-strip-markdown v2.0.1+incompatible
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb
github.com/yuin/goldmark v1.6.0
gopkg.in/yaml.v3 v3.0.1
)

require (
Expand Down Expand Up @@ -63,7 +65,6 @@ require (
golang.org/x/sys v0.15.0 // indirect
golang.org/x/term v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.16
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52 h1:gAQliwn+zJrkjA
github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/twelvelabs/termite v0.13.1 h1:e5m67QY7MKJ7z7e3a59pQTNowptAL4FTCw7xhnPvhto=
github.com/twelvelabs/termite v0.13.1/go.mod h1:2tjVjIRrhqyptjCeevwyNMN+mx25NS5lD1bxb9ka8JA=
github.com/writeas/go-strip-markdown v2.0.1+incompatible h1:IIqxTM5Jr7RzhigcL6FkrCNfXkvbR+Nbu1ls48pXYcw=
github.com/writeas/go-strip-markdown v2.0.1+incompatible/go.mod h1:Rsyu10ZhbEK9pXdk8V6MVnZmTzRG0alMNLMwa0J01fE=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
Expand Down
69 changes: 46 additions & 23 deletions internal/cmd/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/twelvelabs/termite/fsutil"
"github.com/twelvelabs/termite/render"
"github.com/twelvelabs/termite/validate"
stripmd "github.com/writeas/go-strip-markdown"

"github.com/twelvelabs/schemadoc/internal/core"
"github.com/twelvelabs/schemadoc/internal/jsonschema"
Expand All @@ -23,6 +24,9 @@ import (

func init() {
render.FuncMap["toHTML"] = markdown.ToHTMLString
render.FuncMap["wrapCode"] = markdown.WrapCode
render.FuncMap["firstSentence"] = markdown.FirstSentence
render.FuncMap["stripMarkdown"] = stripmd.Strip
}

func NewGenCmd(app *core.App) *cobra.Command {
Expand Down Expand Up @@ -56,7 +60,8 @@ type GenAction struct {

InPath string `validate:"required"`
OutDir string `validate:"required" default:"out"`
OutFile string `validate:"required" default:"{{ .EntityName }}.md"`
OutFile string `validate:"required" default:"{{ .EntityName | underscore }}.md"`
OutFileTpl render.Template
SchemaPaths []string
TemplatePath string
}
Expand All @@ -73,39 +78,51 @@ func (a *GenAction) Run(_ context.Context, _ []string) error {
}

context := jsonschema.NewContext()
scm, err := context.Get(path)
schema, err := context.Get(path)
if err != nil {
return err
}
schema.GenPathTpl = a.OutFileTpl

var rendered string
if a.TemplatePath != "" {
rendered, err = render.File(a.TemplatePath, scm)
} else {
var tpl *template.Template
templatePath := "templates/markdown.tpl.md"
tpl, err = template.New(filepath.Base(templatePath)).
Funcs(render.FuncMap).
ParseFS(jsonschema.Templates, templatePath)
if err != nil {
if err := a.generateSchema(schema); err != nil {
return err
}
for _, subSchema := range schema.Definitions {
if err := a.generateSchema(subSchema); err != nil {
return err
}
buf := bytes.Buffer{}
err = tpl.Execute(&buf, scm)
rendered = buf.String()
}
if err != nil {
return err
}
}

outFile, err := render.String(a.OutFile, scm)
return nil
}

func (a *GenAction) generateSchema(schema *jsonschema.Schema) error {
var rendered string
var err error

if a.TemplatePath != "" {
rendered, err = render.File(a.TemplatePath, schema)
} else {
var tpl *template.Template
templatePath := "templates/markdown.tpl.md"
tpl, err = template.New(filepath.Base(templatePath)).
Funcs(render.FuncMap).
ParseFS(jsonschema.Templates, templatePath)
if err != nil {
return err
}
outPath := filepath.Join(a.OutDir, outFile)
if err := os.WriteFile(outPath, []byte(rendered), fsutil.DefaultFileMode); err != nil {
return err
}
buf := bytes.Buffer{}
err = tpl.Execute(&buf, schema)
rendered = buf.String()
}
if err != nil {
return err
}

outPath := filepath.Join(a.OutDir, schema.GenPath())
if err := os.WriteFile(outPath, []byte(rendered), 0644); err != nil { //nolint: gosec
return err
}

return nil
Expand Down Expand Up @@ -142,6 +159,12 @@ func (a *GenAction) setup() error {
return fmt.Errorf(`'--out': %w`, err)
}

tpl, err := render.Compile(a.OutFile)
if err != nil {
return fmt.Errorf(`'--outfile': %w`, err)
}
a.OutFileTpl = *tpl

if a.TemplatePath != "" {
info, err := os.Stat(a.TemplatePath)
if err != nil {
Expand Down
29 changes: 26 additions & 3 deletions internal/jsonschema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"github.com/gobuffalo/flect"
"github.com/twelvelabs/termite/render"
"gopkg.in/yaml.v3"
)

//go:embed templates/*
Expand Down Expand Up @@ -138,7 +139,7 @@ func (s *Schema) DescriptionMarkdown() string {

func (s *Schema) EntityName() string {
if s.Title != "" {
return s.Title
return flect.Pascalize(s.Title)
}
if s.Key != "" {
return flect.Pascalize(s.Key)
Expand Down Expand Up @@ -186,7 +187,7 @@ func (s *Schema) EnumMarkdown() string {
if idx < len(s.EnumDescriptions) {
desc = s.EnumDescriptions[idx]
}
item := " * `" + enum.String() + "`"
item := "- `" + enum.String() + "`"
if desc != "" {
item += ": " + desc
}
Expand All @@ -204,7 +205,7 @@ func (s *Schema) ExamplesMarkdown() string {
items := []string{}

for _, example := range s.Examples {
items = append(items, fmt.Sprintf(" * `%s`", example.String()))
items = append(items, fmt.Sprintf(" * `%s`", example.YAMLString()))
}

if len(items) == 0 {
Expand Down Expand Up @@ -488,3 +489,25 @@ func (a Any) String() string {
}
return fmt.Sprintf("%v", a.value)
}

func (a Any) JSONString() string {
if a.value == nil {
return ""
}
serialized, err := json.Marshal(a.value)
if err != nil {
return err.Error()
}
return strings.TrimSpace(string(serialized))
}

func (a Any) YAMLString() string {
if a.value == nil {
return ""
}
serialized, err := yaml.Marshal(a.value)
if err != nil {
return err.Error()
}
return strings.TrimSpace(string(serialized))
}
4 changes: 2 additions & 2 deletions internal/jsonschema/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ func TestSchema_EnumMarkdown(t *testing.T) {
{"two"},
},
}
require.Equal(" * `one`\n * `two`", schema.EnumMarkdown())
require.Equal("- `one`\n- `two`", schema.EnumMarkdown())

schema = Schema{
Enum: []Any{
Expand All @@ -167,7 +167,7 @@ func TestSchema_EnumMarkdown(t *testing.T) {
"the second number",
},
}
require.Equal(" * `one`: the first number\n * `two`: the second number", schema.EnumMarkdown())
require.Equal("- `one`: the first number\n- `two`: the second number", schema.EnumMarkdown())
}

func TestSchema_ExamplesMarkdown(t *testing.T) {
Expand Down
82 changes: 60 additions & 22 deletions internal/jsonschema/templates/markdown.tpl.md
Original file line number Diff line number Diff line change
@@ -1,54 +1,92 @@
{{ define "ConstTpl" -}}
{{ if .String }}<p>Allowed value:</p><ul><li><code>{{ .String }}</code></li></ul>{{ end -}}
{{ if . -}}

Allowed Value:

- `{{ . }}`

{{ end -}}
{{ end -}}

{{ define "DescriptionTpl" -}}
{{ if . -}}

{{ . }}

{{ end -}}
{{ end -}}

{{ define "EnumTpl" -}}
{{ if . }}<p>Allowed values:</p>{{ . | toHTML }}{{ end -}}
{{ if . -}}

Allowed Values:

{{ . }}

{{ end -}}
{{ end -}}

{{ define "ExamplesTpl" -}}
{{ if . }}<p>Examples:</p>{{ . | toHTML }}{{ end -}}
{{ if . -}}

Examples:

{{ range $example := . -}}

```yaml
{{ $example.YAMLString }}
```

{{ end -}}
{{ end -}}
{{ end -}}

{{ define "PropertiesTpl" -}}
{{ if . -}}
| Property | Type | Required | Default | Description |
| -------- | ---- | -------- | ------- | ----------- |
| Property | Type | Required | Enum | Default | Description |
| -------- | ---- | -------- | ---- | ------- | ----------- |
{{ $propParent := . -}}
{{ range $key, $prop := $propParent.Properties -}}
| `{{ $key }}` | {{ $prop.TypeInfoMarkdown }} | {{ if $propParent.RequiredKey $key }}✅{{ end }} | {{ $prop.Default }} | {{ $prop.DescriptionMarkdown | toHTML }}{{ template "ConstTpl" $prop.Const }}{{ template "EnumTpl" $prop.EnumMarkdown }}{{ template "ExamplesTpl" $prop.ExamplesMarkdown }} |
| [`{{ $key }}`](#{{ $key }}) | {{ $prop.TypeInfoMarkdown }} | {{ if $propParent.RequiredKey $key }}✅{{ else }}➖{{ end }} | {{ if $prop.Enum }}✅{{ else }}➖{{ end }} | {{ $prop.Default.JSONString | wrapCode | default "➖" }} | {{ $prop.DescriptionMarkdown | stripMarkdown | firstSentence | toHTML }} |
{{ end -}}
{{ end -}}
{{ end -}}

# {{ .EntityName }}

{{ .DescriptionMarkdown }}
{{ template "DescriptionTpl" .DescriptionMarkdown }}
{{ template "ConstTpl" .Const.String }}
{{ template "EnumTpl" .EnumMarkdown }}
{{ template "ExamplesTpl" .Examples }}

## {{ .EntityName }} Properties
{{ if .OneOf -}}

{{ template "PropertiesTpl" . }}
{{ range $key, $def := .Definitions -}}
{{ if $def.Enum }}{{ continue }}{{ end -}}
## Variants

## {{ $def.EntityName }}
{{ range $key, $schema := .OneOf -}}

{{ $def.DescriptionMarkdown }}
- [{{ $schema.EntityName }}]({{ $schema.EntityLink }})
{{ end -}}
{{ end -}}
{{ if .Properties -}}

{{ if $def.Properties -}}
## Properties

### {{ $def.EntityName }} Properties
{{ template "PropertiesTpl" . }}

{{ template "PropertiesTpl" $def }}
{{ end -}}
{{ $root := . -}}
{{ range $key, $prop := .Properties -}}

{{ if $def.OneOf -}}
### `{{ $key }}`

### {{ $def.EntityName }} Variants
| Type | Required | Enum | Default |
| ---- | -------- | ---- | ------- |
| {{ $prop.TypeInfoMarkdown }} | {{ if $root.RequiredKey $key }}✅{{ else }}➖{{ end }} | {{ if $prop.Enum }}✅{{ else }}➖{{ end }} | {{ $prop.Default.JSONString | wrapCode | default "➖" }} |

{{ range $key, $subSchema := $def.OneOf -}}
{{ template "DescriptionTpl" $prop.DescriptionMarkdown }}
{{ template "ConstTpl" $prop.Const.String }}
{{ template "EnumTpl" $prop.EnumMarkdown }}
{{ template "ExamplesTpl" $prop.Examples }}

- [{{ $subSchema.EntityName }}]({{ $subSchema.EntityLink }})
{{ end }}
{{ end -}}
{{ end -}}
Loading

0 comments on commit 73d9a66

Please sign in to comment.