Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: generic arrays generate successfully #1247

Merged
merged 1 commit into from Jun 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 14 additions & 5 deletions generics.go
Expand Up @@ -94,11 +94,8 @@ func (pkgDefs *PackagesDefinitions) parametrizeStruct(original *TypeSpecDef, ful
Tag: field.Tag,
Comment: field.Comment,
}
if genTypeSpec, ok := genericParamTypeDefs[field.Type.(*ast.Ident).Name]; ok {
newField.Type = genTypeSpec.TypeSpec.Type
} else {
newField.Type = field.Type
}

newField.Type = resolveType(field.Type, field, genericParamTypeDefs)

newStructTypeDef.Fields.List = append(newStructTypeDef.Fields.List, newField)
}
Expand All @@ -107,3 +104,15 @@ func (pkgDefs *PackagesDefinitions) parametrizeStruct(original *TypeSpecDef, ful

return parametrizedTypeSpec
}

func resolveType(expr ast.Expr, field *ast.Field, genericParamTypeDefs map[string]*TypeSpecDef) ast.Expr {
if asIdent, ok := expr.(*ast.Ident); ok {
if genTypeSpec, ok := genericParamTypeDefs[asIdent.Name]; ok {
return genTypeSpec.TypeSpec.Type
}
} else if asArray, ok := expr.(*ast.ArrayType); ok {
return &ast.ArrayType{Elt: resolveType(asArray.Elt, field, genericParamTypeDefs), Len: asArray.Len, Lbrack: asArray.Lbrack}
}

return field.Type
}
168 changes: 168 additions & 0 deletions generics_test.go
Expand Up @@ -207,3 +207,171 @@ func TestParseGenericsBasic(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, expected, string(b))
}

func TestParseGenericsArrays(t *testing.T) {
t.Parallel()

expected := `{
"swagger": "2.0",
"info": {
"description": "This is a sample server Petstore server.",
"title": "Swagger Example API",
"contact": {},
"version": "1.0"
},
"host": "localhost:4000",
"basePath": "/api",
"paths": {
"/posts": {
"get": {
"description": "Get All of the Posts",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "List Posts",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/web.GenericListResponse-web_Post"
}
},
"222": {
"description": "",
"schema": {
"$ref": "#/definitions/web.GenericListResponseMulti-web_Post-web_Post"
}
}
}
}
}
},
"definitions": {
"web.GenericListResponse-web_Post": {
"type": "object",
"properties": {
"items": {
"description": "Items from the list response",
"type": "array",
"items": {
"type": "object",
"properties": {
"data": {
"description": "Post data",
"type": "object",
"properties": {
"name": {
"description": "Post tag",
"type": "array",
"items": {
"type": "string"
}
}
}
},
"id": {
"type": "integer",
"format": "int64",
"example": 1
},
"name": {
"description": "Post name",
"type": "string",
"example": "poti"
}
}
}
},
"status": {
"description": "Status of some other stuff",
"type": "string"
}
}
},
"web.GenericListResponseMulti-web_Post-web_Post": {
"type": "object",
"properties": {
"itemsOne": {
"description": "ItemsOne is the first thing",
"type": "array",
"items": {
"type": "object",
"properties": {
"data": {
"description": "Post data",
"type": "object",
"properties": {
"name": {
"description": "Post tag",
"type": "array",
"items": {
"type": "string"
}
}
}
},
"id": {
"type": "integer",
"format": "int64",
"example": 1
},
"name": {
"description": "Post name",
"type": "string",
"example": "poti"
}
}
}
},
"itemsTwo": {
"description": "ItemsTwo is the second thing",
"type": "array",
"items": {
"type": "object",
"properties": {
"data": {
"description": "Post data",
"type": "object",
"properties": {
"name": {
"description": "Post tag",
"type": "array",
"items": {
"type": "string"
}
}
}
},
"id": {
"type": "integer",
"format": "int64",
"example": 1
},
"name": {
"description": "Post name",
"type": "string",
"example": "poti"
}
}
}
},
"status": {
"description": "Status of the things",
"type": "string"
}
}
}
}
}`

searchDir := "testdata/generics_arrays"
p := New()
err := p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)
assert.NoError(t, err)
b, err := json.MarshalIndent(p.swagger, "", " ")
assert.NoError(t, err)
assert.Equal(t, expected, string(b))
}
18 changes: 18 additions & 0 deletions testdata/generics_arrays/api/api.go
@@ -0,0 +1,18 @@
package api

import (
"net/http"

"github.com/swaggo/swag/testdata/generics_arrays/web"
)

// @Summary List Posts
// @Description Get All of the Posts
// @Accept json
// @Produce json
// @Success 200 {object} web.GenericListResponse[web.Post]
// @Success 222 {object} web.GenericListResponseMulti[web.Post, web.Post]
// @Router /posts [get]
func GetPosts(w http.ResponseWriter, r *http.Request) {
_ = web.GenericListResponse[web.Post]{}
}
17 changes: 17 additions & 0 deletions testdata/generics_arrays/main.go
@@ -0,0 +1,17 @@
package main

import (
"net/http"

"github.com/swaggo/swag/testdata/generics_basic/api"
)

// @title Swagger Example API
// @version 1.0
// @description This is a sample server Petstore server.
// @host localhost:4000
// @basePath /api
func main() {
http.HandleFunc("/posts/", api.GetPost)
http.ListenAndServe(":8080", nil)
}
50 changes: 50 additions & 0 deletions testdata/generics_arrays/web/handler.go
@@ -0,0 +1,50 @@
package web

import (
"time"
)

// GenericListResponse[T]
// @Description Some Generic List Response
type GenericListResponse[T any] struct {
// Items from the list response
Items []T
// Status of some other stuff
Status string
}

// GenericListResponseMulti[T, X]
// @Description this contains a few things
type GenericListResponseMulti[T any, X any] struct {
// ItemsOne is the first thing
ItemsOne []T
// ItemsTwo is the second thing
ItemsTwo []X

// Status of the things
Status string
}

type Post struct {
ID int `json:"id" example:"1" format:"int64"`
// Post name
Name string `json:"name" example:"poti"`
// Post data
Data struct {
// Post tag
Tag []string `json:"name"`
} `json:"data"`
}

// APIError
// @Description API error
// @Description with information about it
// Other some summary
type APIError struct {
// Error an Api error
Error string // Error this is Line comment
// Error `number` tick comment
ErrorNo int64
ErrorCtx string // Error `context` tick comment
CreatedAt time.Time // Error time
}