Skip to content

Commit

Permalink
make breadcrumb more readable
Browse files Browse the repository at this point in the history
  • Loading branch information
arvidfm committed Jan 30, 2024
1 parent de24ea5 commit 2a5a5ef
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 25 deletions.
44 changes: 35 additions & 9 deletions comment_extractor.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package jsonschema

import (
"fmt"
"go/ast"
"go/doc"
"go/parser"
Expand All @@ -12,7 +11,33 @@ import (
"strings"
)

func handleType(expr ast.Expr, breadcrumb string, comments map[string]string) {
type breadcrumb []string

func (b breadcrumb) With(breadcrumb string) breadcrumb {
return append(b, breadcrumb)
}

func (b breadcrumb) Field(fieldName string) breadcrumb {
return b.With(fieldName)
}

func (b breadcrumb) SliceElem() breadcrumb {
return b.With("[]")
}

func (b breadcrumb) MapKey() breadcrumb {
return b.With("[key]")
}

func (b breadcrumb) MapElem() breadcrumb {
return b.With("[value]")
}

func (b breadcrumb) String() string {
return strings.Join(b, ".")
}

func handleType(expr ast.Expr, breadcrumb breadcrumb, comments map[string]string) {
switch t := expr.(type) {
case *ast.StructType:
for _, field := range t.Fields.List {
Expand All @@ -21,20 +46,20 @@ func handleType(expr ast.Expr, breadcrumb string, comments map[string]string) {
continue
}

b := fmt.Sprintf("%s.%s", breadcrumb, name.Name)
b := breadcrumb.Field(name.Name)
txt := field.Doc.Text()
if txt == "" {
txt = field.Comment.Text()
}
comments[b] = strings.TrimSpace(txt)
comments[b.String()] = strings.TrimSpace(txt)
handleType(field.Type, b, comments)
}
}
case *ast.ArrayType:
handleType(t.Elt, fmt.Sprintf("%s.[]", breadcrumb), comments)
handleType(t.Elt, breadcrumb.SliceElem(), comments)
case *ast.MapType:
handleType(t.Key, fmt.Sprintf("%s.[key]", breadcrumb), comments)
handleType(t.Value, fmt.Sprintf("%s.[value]", breadcrumb), comments)
handleType(t.Key, breadcrumb.MapKey(), comments)
handleType(t.Value, breadcrumb.MapElem(), comments)
case *ast.StarExpr:
handleType(t.X, breadcrumb, comments)
}
Expand Down Expand Up @@ -80,6 +105,7 @@ func ExtractGoComments(base, path string, commentMap map[string]string) error {
}

for qualifiedName, pkg := range pkgs {
rootBreadcrumb := breadcrumb{qualifiedName}
for _, file := range pkg.Files {
for _, decl := range file.Decls {
if d, ok := decl.(*ast.GenDecl); ok {
Expand All @@ -89,12 +115,12 @@ func ExtractGoComments(base, path string, commentMap map[string]string) error {
continue
}

breadcrumb := fmt.Sprintf("%s.%s", qualifiedName, s.Name.Name)
breadcrumb := rootBreadcrumb.With(s.Name.Name)
txt := s.Doc.Text()
if txt == "" {
txt = d.Doc.Text()
}
commentMap[breadcrumb] = strings.TrimSpace(doc.Synopsis(txt))
commentMap[breadcrumb.String()] = strings.TrimSpace(doc.Synopsis(txt))
handleType(s.Type, breadcrumb, commentMap)
}
}
Expand Down
31 changes: 15 additions & 16 deletions reflect.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ package jsonschema
import (
"bytes"
"encoding/json"
"fmt"
"net"
"net/url"
"reflect"
Expand Down Expand Up @@ -177,7 +176,7 @@ func (r *Reflector) ReflectFromType(t reflect.Type) *Schema {
s := new(Schema)
definitions := Definitions{}
s.Definitions = definitions
bs := r.reflectTypeToSchemaWithID(definitions, t, "")
bs := r.reflectTypeToSchemaWithID(definitions, t, breadcrumb{})
if r.ExpandedStruct {
*s = *definitions[name]
delete(definitions, name)
Expand Down Expand Up @@ -235,7 +234,7 @@ func (r *Reflector) SetBaseSchemaID(id string) {
r.BaseSchemaID = ID(id)
}

func (r *Reflector) refOrReflectTypeToSchema(definitions Definitions, t reflect.Type, breadcrumb string) *Schema {
func (r *Reflector) refOrReflectTypeToSchema(definitions Definitions, t reflect.Type, breadcrumb breadcrumb) *Schema {
id := r.lookupID(t)
if id != EmptyID {
return &Schema{
Expand All @@ -251,7 +250,7 @@ func (r *Reflector) refOrReflectTypeToSchema(definitions Definitions, t reflect.
return r.reflectTypeToSchemaWithID(definitions, t, breadcrumb)
}

func (r *Reflector) reflectTypeToSchemaWithID(defs Definitions, t reflect.Type, breadcrumb string) *Schema {
func (r *Reflector) reflectTypeToSchemaWithID(defs Definitions, t reflect.Type, breadcrumb breadcrumb) *Schema {
s := r.reflectTypeToSchema(defs, t, breadcrumb)
if s != nil {
if r.Lookup != nil {
Expand All @@ -264,7 +263,7 @@ func (r *Reflector) reflectTypeToSchemaWithID(defs Definitions, t reflect.Type,
return s
}

func (r *Reflector) reflectTypeToSchema(definitions Definitions, t reflect.Type, breadcrumb string) *Schema {
func (r *Reflector) reflectTypeToSchema(definitions Definitions, t reflect.Type, breadcrumb breadcrumb) *Schema {
// only try to reflect non-pointers
if t.Kind() == reflect.Ptr {
return r.refOrReflectTypeToSchema(definitions, t.Elem(), breadcrumb)
Expand Down Expand Up @@ -389,7 +388,7 @@ func (r *Reflector) reflectSchemaExtend(definitions Definitions, t reflect.Type,
return s
}

func (r *Reflector) reflectSliceOrArray(definitions Definitions, t reflect.Type, st *Schema, breadcrumb string) {
func (r *Reflector) reflectSliceOrArray(definitions Definitions, t reflect.Type, st *Schema, breadcrumb breadcrumb) {
if t == rawMessageType {
return
}
Expand All @@ -411,19 +410,19 @@ func (r *Reflector) reflectSliceOrArray(definitions Definitions, t reflect.Type,
st.ContentEncoding = "base64"
} else {
st.Type = "array"
st.Items = r.refOrReflectTypeToSchema(definitions, t.Elem(), fmt.Sprintf("%s.[]", breadcrumb))
st.Items = r.refOrReflectTypeToSchema(definitions, t.Elem(), breadcrumb.SliceElem())
}
}

func (r *Reflector) reflectMap(definitions Definitions, t reflect.Type, st *Schema, breadcrumb string) {
func (r *Reflector) reflectMap(definitions Definitions, t reflect.Type, st *Schema, breadcrumb breadcrumb) {
r.addDefinition(definitions, t, st)

st.Type = "object"
if st.Description == "" {
st.Description = r.lookupComment(breadcrumb)
}

valueBreadcrumb := fmt.Sprintf("%s.[value]", breadcrumb)
valueBreadcrumb := breadcrumb.MapElem()
switch t.Key().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
st.PatternProperties = map[string]*Schema{
Expand All @@ -438,7 +437,7 @@ func (r *Reflector) reflectMap(definitions Definitions, t reflect.Type, st *Sche
}

// Reflects a struct to a JSON Schema type.
func (r *Reflector) reflectStruct(definitions Definitions, t reflect.Type, s *Schema, breadcrumb string) {
func (r *Reflector) reflectStruct(definitions Definitions, t reflect.Type, s *Schema, breadcrumb breadcrumb) {
// Handle special types
switch t {
case timeType: // date-time RFC section 7.3.1
Expand Down Expand Up @@ -474,7 +473,7 @@ func (r *Reflector) reflectStruct(definitions Definitions, t reflect.Type, s *Sc
}
}

func (r *Reflector) reflectStructFields(st *Schema, definitions Definitions, t reflect.Type, breadcrumb string) {
func (r *Reflector) reflectStructFields(st *Schema, definitions Definitions, t reflect.Type, breadcrumb breadcrumb) {
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
Expand Down Expand Up @@ -509,7 +508,7 @@ func (r *Reflector) reflectStructFields(st *Schema, definitions Definitions, t r
return
}

fieldBreadcrumb := fmt.Sprintf("%s.%s", breadcrumb, f.Name)
fieldBreadcrumb := breadcrumb.Field(f.Name)
// If a JSONSchemaAlias(prop string) method is defined, attempt to use
// the provided object's type instead of the field's type.
var property *Schema
Expand Down Expand Up @@ -566,12 +565,12 @@ func appendUniqueString(base []string, value string) []string {
return append(base, value)
}

func (r *Reflector) lookupComment(breadcrumb string) string {
func (r *Reflector) lookupComment(breadcrumb breadcrumb) string {
if r.CommentMap == nil {
return ""
}

return r.CommentMap[breadcrumb]
return r.CommentMap[breadcrumb.String()]
}

// addDefinition will append the provided schema. If needed, an ID and anchor will also be added.
Expand Down Expand Up @@ -1138,8 +1137,8 @@ func splitOnUnescapedCommas(tagString string) []string {
return ret
}

func fullyQualifiedTypeName(t reflect.Type) string {
return t.PkgPath() + "." + t.Name()
func fullyQualifiedTypeName(t reflect.Type) breadcrumb {
return breadcrumb{t.PkgPath(), t.Name()}
}

// AddGoComments will update the reflectors comment map with all the comments
Expand Down

0 comments on commit 2a5a5ef

Please sign in to comment.