From 42b64e58ab10cad7cad3bd7e60825ac6c6f462c4 Mon Sep 17 00:00:00 2001 From: Rafael Dantas Justo Date: Tue, 4 Mar 2025 14:15:11 -0300 Subject: [PATCH] Fix: Improve maps support * Correctly handle an array of maps * Avoid adding an `any` additional property (invalid swagger type) --- README.md | 2 +- docparse/docparse_test.go | 18 +++++++++++++++++- docparse/find.go | 2 ++ docparse/jsonschema.go | 8 +++++++- testdata/openapi2/src/struct-map/in.go | 1 + testdata/openapi2/src/struct-map/want.yaml | 3 +++ testdata/openapi2/src/struct-slice/in.go | 4 ++++ testdata/openapi2/src/struct-slice/want.yaml | 5 +++++ 8 files changed, 40 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b42af95..fc8a950 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ Kommentaar can be configured with a configuration file; see Running Tests ------------- -`GO111MODULE=off ./bin/test ./...` +`GO111MODULE=off go test ./...` Motivation and rationale ------------------------ diff --git a/docparse/docparse_test.go b/docparse/docparse_test.go index 5eb4b61..fb869f4 100644 --- a/docparse/docparse_test.go +++ b/docparse/docparse_test.go @@ -521,7 +521,23 @@ func TestGetReference(t *testing.T) { }}, {"UnknownObject", "could not find", nil}, - {"net/http.Header", "not a struct", nil}, + {"net/http.Header", "", &Reference{ + Name: "Header", + Package: "net/http", + Lookup: "http.Header", + Info: "A Header represents the key-value pairs in an HTTP header.\n\n" + + "The keys should be in canonical form, as returned by\n" + + "[CanonicalHeaderKey].", + Context: "req", + Schema: &Schema{ + Title: "Header", + Description: "A Header represents the key-value pairs in an HTTP header.\n\n" + + "The keys should be in canonical form, as returned by\n" + + "[CanonicalHeaderKey].", + Type: "object", + Properties: map[string]*Schema{}, + }, + }}, } for _, tt := range tests { diff --git a/docparse/find.go b/docparse/find.go index c81a93a..321165f 100644 --- a/docparse/find.go +++ b/docparse/find.go @@ -335,6 +335,8 @@ func GetReference(prog *Program, context string, isEmbed bool, lookup, filePath arLookup = fmt.Sprintf("[%v:%v]", wrapper, arLookup) } return GetReference(prog, context, isEmbed, arLookup, filePath) + case *ast.MapType: + st = &ast.StructType{Fields: &ast.FieldList{}} default: return nil, ErrNotStruct{ts, fmt.Sprintf( "%v is not a struct or interface but a %T", name, ts.Type)} diff --git a/docparse/jsonschema.go b/docparse/jsonschema.go index 9d507f7..24a5a71 100644 --- a/docparse/jsonschema.go +++ b/docparse/jsonschema.go @@ -408,7 +408,9 @@ start: } if isPrimitive(vtyp.Name) { // we are done, no need for a lookup of a custom type - p.AdditionalProperties = &Schema{Type: JSONSchemaType(vtyp.Name)} + if vtyp.Name != "any" { + p.AdditionalProperties = &Schema{Type: JSONSchemaType(vtyp.Name)} + } return &p, nil } @@ -705,6 +707,10 @@ arrayStart: pkg = importPath } + case *ast.MapType: + p.Items = &Schema{Type: "object"} + return nil + default: return fmt.Errorf("fieldToSchema: unknown array type: %T", typ) } diff --git a/testdata/openapi2/src/struct-map/in.go b/testdata/openapi2/src/struct-map/in.go index 7e244c5..ec3ebd1 100644 --- a/testdata/openapi2/src/struct-map/in.go +++ b/testdata/openapi2/src/struct-map/in.go @@ -4,6 +4,7 @@ import "struct-map/otherpkg" type resp struct { Basic map[string]interface{} `json:"basic"` // Basic comment. + Basic2 map[string]any `json:"basic2"` // Basic2 comment. Custom myMap `json:"custom"` // Custom comment. Struct aStruct `json:"aStruct"` // Struct comment. OtherStruct otherpkg.OtherStruct `json:"otherStruct"` // OtherStruct comment. diff --git a/testdata/openapi2/src/struct-map/want.yaml b/testdata/openapi2/src/struct-map/want.yaml index 44f38fb..a2ea06a 100644 --- a/testdata/openapi2/src/struct-map/want.yaml +++ b/testdata/openapi2/src/struct-map/want.yaml @@ -43,6 +43,9 @@ definitions: basic: description: Basic comment. type: object + basic2: + description: Basic2 comment. + type: object custom: description: Custom comment. type: object diff --git a/testdata/openapi2/src/struct-slice/in.go b/testdata/openapi2/src/struct-slice/in.go index 6d288bc..03d8761 100644 --- a/testdata/openapi2/src/struct-slice/in.go +++ b/testdata/openapi2/src/struct-slice/in.go @@ -4,6 +4,7 @@ type resp struct { Basic []string `json:"basic"` // Basic comment. Custom mySlice `json:"custom"` // Custom comment. Double anotherSlice `json:"another"` // Double comment. + OneMore oneMoreSlice `json:"oneMore"` // OneMore comment. StructRef customFieldValues `json:"structRef"` // structRefComment. Deal deal `json:"deal"` } @@ -14,6 +15,9 @@ type mySlice []string // anotherSlice comment. type anotherSlice mySlice +// oneMoreSlice comment. +type oneMoreSlice []map[string]any + type customFieldValues []*customFieldValue type customFieldValue struct { diff --git a/testdata/openapi2/src/struct-slice/want.yaml b/testdata/openapi2/src/struct-slice/want.yaml index 3259f25..b2e5113 100644 --- a/testdata/openapi2/src/struct-slice/want.yaml +++ b/testdata/openapi2/src/struct-slice/want.yaml @@ -53,6 +53,11 @@ definitions: type: string deal: $ref: '#/definitions/struct-slice.deal' + oneMore: + description: OneMore comment. + type: array + items: + type: object structRef: description: structRefComment. type: array