Skip to content

Commit

Permalink
openapi3: move ref codegen to Go (#956)
Browse files Browse the repository at this point in the history
* Move ref code gen from bash to go

Keeps things in the go ecosystem and it will make a change
I'll like to do far easier with go available.

No changes to the generated refs.go other than a warning that it's
generated to devs and IDEs.

* Re-run ./docs.sh
  • Loading branch information
percivalalb committed Jun 2, 2024
1 parent 45b4399 commit 518b18d
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 42 deletions.
2 changes: 2 additions & 0 deletions .github/docs/openapi3.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Package openapi3 parses and writes OpenAPI 3 specification documents.

See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md

Code generated by go generate; DO NOT EDIT.

CONSTANTS

const (
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:

- uses: actions/checkout@v2

- run: ./refs.sh | tee openapi3/refs.go
- run: go generate openapi3/refsgenerator.go
- run: git --no-pager diff --exit-code

- run: ./maps.sh
Expand Down
2 changes: 2 additions & 0 deletions openapi3/ref.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package openapi3

//go:generate go run refsgenerator.go

// Ref is specified by OpenAPI/Swagger 3.0 standard.
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#reference-object
type Ref struct {
Expand Down
1 change: 1 addition & 0 deletions openapi3/refs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 19 additions & 41 deletions refs.sh → openapi3/refs.tmpl
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
#!/bin/bash -eux
set -o pipefail

types=()
types+=("Callback")
types+=("Example")
types+=("Header")
types+=("Link")
types+=("Parameter")
types+=("RequestBody")
types+=("Response")
types+=("Schema")
types+=("SecurityScheme")

cat <<EOF
package openapi3
// Code generated by go generate; DO NOT EDIT.
package {{ .Package }}

import (
"context"
Expand All @@ -24,44 +10,38 @@ import (
"github.com/go-openapi/jsonpointer"
"github.com/perimeterx/marshmallow"
)
EOF

for type in "${types[@]}"; do
cat <<EOF
// ${type}Ref represents either a ${type} or a \$ref to a ${type}.
{{ range $type := .Types }}
// {{ $type }}Ref represents either a {{ $type }} or a $ref to a {{ $type }}.
// When serializing and both fields are set, Ref is preferred over Value.
type ${type}Ref struct {
type {{ $type }}Ref struct {
Ref string
Value *${type}
Value *{{ $type }}
extra []string
}

var _ jsonpointer.JSONPointable = (*${type}Ref)(nil)
var _ jsonpointer.JSONPointable = (*{{ $type }}Ref)(nil)

func (x *${type}Ref) isEmpty() bool { return x == nil || x.Ref == "" && x.Value == nil }
func (x *{{ $type }}Ref) isEmpty() bool { return x == nil || x.Ref == "" && x.Value == nil }

// MarshalYAML returns the YAML encoding of ${type}Ref.
func (x ${type}Ref) MarshalYAML() (interface{}, error) {
// MarshalYAML returns the YAML encoding of {{ $type }}Ref.
func (x {{ $type }}Ref) MarshalYAML() (interface{}, error) {
if ref := x.Ref; ref != "" {
return &Ref{Ref: ref}, nil
}
return x.Value.MarshalYAML()
}

// MarshalJSON returns the JSON encoding of ${type}Ref.
func (x ${type}Ref) MarshalJSON() ([]byte, error) {
// MarshalJSON returns the JSON encoding of {{ $type }}Ref.
func (x {{ $type }}Ref) MarshalJSON() ([]byte, error) {
y, err := x.MarshalYAML()
if err != nil {
return nil, err
}
return json.Marshal(y)
EOF
cat <<EOF
}

// UnmarshalJSON sets ${type}Ref to a copy of data.
func (x *${type}Ref) UnmarshalJSON(data []byte) error {
// UnmarshalJSON sets {{ $type }}Ref to a copy of data.
func (x *{{ $type }}Ref) UnmarshalJSON(data []byte) error {
var refOnly Ref
if extra, err := marshmallow.Unmarshal(data, &refOnly, marshmallow.WithExcludeKnownFieldsFromMap(true)); err == nil && refOnly.Ref != "" {
x.Ref = refOnly.Ref
Expand All @@ -77,8 +57,8 @@ func (x *${type}Ref) UnmarshalJSON(data []byte) error {
return json.Unmarshal(data, &x.Value)
}

// Validate returns an error if ${type}Ref does not comply with the OpenAPI spec.
func (x *${type}Ref) Validate(ctx context.Context, opts ...ValidationOption) error {
// Validate returns an error if {{ $type }}Ref does not comply with the OpenAPI spec.
func (x *{{ $type }}Ref) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)
if extra := x.extra; len(extra) != 0 {
extras := make([]string, 0, len(extra))
Expand All @@ -102,13 +82,11 @@ func (x *${type}Ref) Validate(ctx context.Context, opts ...ValidationOption) err
}

// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
func (x *${type}Ref) JSONLookup(token string) (interface{}, error) {
if token == "\$ref" {
func (x *{{ $type }}Ref) JSONLookup(token string) (interface{}, error) {
if token == "$ref" {
return x.Ref, nil
}
ptr, _, err := jsonpointer.GetForToken(x.Value, token)
return ptr, err
}
EOF

done
{{ end -}}
49 changes: 49 additions & 0 deletions openapi3/refsgenerator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//go:build ignore
// +build ignore

// The program generates refs.go, invoke `go generate ./...` to run.
package main

import (
_ "embed"
"os"
"text/template"
)

//go:embed refs.tmpl
var tmplData string

func main() {
file, err := os.Create("refs.go")
if err != nil {
panic(err)
}

defer func() {
if err := file.Close(); err != nil {
panic(err)
}
}()

packageTemplate := template.Must(template.New("openapi3-refs").Parse(tmplData))

if err := packageTemplate.Execute(file, struct {
Package string
Types []string
}{
Package: os.Getenv("GOPACKAGE"), // set by the go:generate directive
Types: []string{
"Callback",
"Example",
"Header",
"Link",
"Parameter",
"RequestBody",
"Response",
"Schema",
"SecurityScheme",
},
}); err != nil {
panic(err)
}
}

0 comments on commit 518b18d

Please sign in to comment.