Skip to content

Commit e8fffa0

Browse files
committed
feat: struct recycle check
1 parent 4e3f6b6 commit e8fffa0

File tree

5 files changed

+111
-68
lines changed

5 files changed

+111
-68
lines changed

examples/docs/apis-greeter.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,43 @@ GET /greeter
1919
{ //object(main.Response), 通用返回结果
2020
"code": 0, //int, 返回状态码
2121
"data": { //object(main.TestData)
22+
"Int": 123, //int
2223
"Map2": { //object(main.TestData2)
23-
"abc": null //object
24+
"abc": { //object(main.TestData2)
25+
"MyAge2": 123, //int
26+
"MyTitle2": "abc" //string, 标题2
27+
}
2428
},
2529
"Map3": { //object(main.TestData2)
2630
"abc": { //object(main.TestData2)
2731
"MyAge2": 123, //int
2832
"MyTitle2": "abc" //string, 标题2
2933
}
3034
},
35+
"Map4": { //object(main.Node)
36+
"123": { //object(main.Node)
37+
"Name": "abc", //string
38+
"Nodes": { //object(main.Node)
39+
"abc": null //object
40+
}
41+
}
42+
},
43+
"MyFloat32": 1.23, //float32
44+
"MyFloat64": 1.23, //float64
45+
"MyInt": 123, //int
46+
"MyIntArray": [ //array[int]
47+
123
48+
],
49+
"MyIntData": 123, //int
3150
"MyInts": [ //array[int]
3251
123
3352
],
53+
"MyTestData2Array": [ //array[main.TestData2]
54+
{ //object(main.TestData2)
55+
"MyAge2": 123, //int
56+
"MyTitle2": "abc" //string, 标题2
57+
}
58+
],
3459
"Nodes": { //object(main.Node)
3560
"abc": { //object(main.Node)
3661
"Name": "abc", //string
@@ -43,7 +68,8 @@ GET /greeter
4368
"data2": { //object(main.TestData2)
4469
"MyAge2": 123, //int
4570
"MyTitle2": "abc" //string, 标题2
46-
}
71+
},
72+
"my_title": "abc" //string, 标题
4773
},
4874
"msg": "返回消息" //string, 返回文本消息
4975
}

examples/main.go

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,20 +39,21 @@ type Node struct {
3939
Nodes map[string]Node
4040
}
4141
type TestData struct {
42-
// MyTitle string `json:"my_title,omitempty"` //标题
43-
Data2 *TestData2 `json:"data2,omitempty"`
44-
// MyIntData int
45-
// MyFloat64 float64
46-
// MyFloat32 float32
47-
// MyIntArray []int
48-
// MyTestData2Array []TestData2
49-
// Int *int
50-
// MyInt MyInt
51-
MyInts []MyInt
52-
Map Map `json:"amap"`
53-
Map2 Map2
54-
Map3 map[string]TestData2
55-
Nodes map[string]Node
42+
MyTitle string `json:"my_title,omitempty"` //标题
43+
Data2 *TestData2 `json:"data2,omitempty"`
44+
MyIntData int
45+
MyFloat64 float64
46+
MyFloat32 float32
47+
MyIntArray []int
48+
MyTestData2Array []TestData2
49+
Int *int
50+
MyInt MyInt
51+
MyInts []MyInt
52+
Map Map `json:"amap"`
53+
Map2 Map2
54+
Map3 map[string]TestData2
55+
Nodes map[string]Node
56+
Map4 map[int]Node
5657
}
5758

5859
type Request struct {

operation.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ func (operation *Operation) ParseRequestComment(commentLine string, astFile *ast
127127
case IsGolangPrimitiveType(refType):
128128
return nil
129129
default:
130-
schema, err := operation.parser.getTypeSchema(refType, astFile, nil)
130+
schema, err := operation.parser.getTypeSchema(refType, astFile, nil, nil)
131131
if err != nil {
132132
return err
133133
}
@@ -160,12 +160,7 @@ func (operation *Operation) ParseRequestComment(commentLine string, astFile *ast
160160
// ParseResponseComment parses comment for given `response` comment string.
161161
func (operation *Operation) ParseResponseComment(commentLine string, astFile *ast.File) error {
162162
operation.parser.clearStructStack()
163-
fmt.Println(commentLine)
164163
matches := responsePattern.FindStringSubmatch(commentLine)
165-
// for i, m := range matches {
166-
// fmt.Println(i, m)
167-
// }
168-
// fmt.Println(commentLine, len(matches))
169164
if len(matches) != 4 && len(matches) != 3 {
170165
return nil
171166
}
@@ -205,7 +200,7 @@ func (operation *Operation) parseObject(refType string, astFile *ast.File) (*Typ
205200
case strings.Contains(refType, "{"):
206201
return operation.parseCombinedObject(refType, astFile)
207202
default:
208-
schema, err := operation.parser.getTypeSchema(refType, astFile, nil)
203+
schema, err := operation.parser.getTypeSchema(refType, astFile, nil, nil)
209204
if err != nil {
210205
return nil, err
211206
}

parser.go

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ func fullTypeName(pkgName, typeName string) string {
352352
return typeName
353353
}
354354

355-
func (parser *Parser) getTypeSchema(typeName string, file *ast.File, field *ast.Field) (*TypeSchema, error) {
355+
func (parser *Parser) getTypeSchema(typeName string, file *ast.File, field *ast.Field, parentSchema *TypeSchema) (*TypeSchema, error) {
356356
if IsGolangPrimitiveType(typeName) {
357357
name := field.Names[0].Name
358358
isOmitempty, fieldName := getFieldName(name, field, "json")
@@ -367,6 +367,7 @@ func (parser *Parser) getTypeSchema(typeName string, file *ast.File, field *ast.
367367
Validate: getValidateTagValue(field),
368368
Tags: getParameterTags(field),
369369
Required: getRequiredTagValue(field),
370+
Parent: parentSchema,
370371
}, nil
371372
}
372373

@@ -376,7 +377,7 @@ func (parser *Parser) getTypeSchema(typeName string, file *ast.File, field *ast.
376377
}
377378
fmt.Println("typeSpecDef", typeSpecDef.Name())
378379

379-
schema, err := parser.ParseDefinition(typeSpecDef, field)
380+
schema, err := parser.ParseDefinition(typeSpecDef, field, parentSchema)
380381
if err != nil {
381382
return nil, err
382383
}
@@ -407,22 +408,21 @@ func (parser *Parser) clearStructStack() {
407408

408409
// ParseDefinition parses given type spec that corresponds to the type under
409410
// given name and package
410-
func (parser *Parser) ParseDefinition(typeSpecDef *TypeSpecDef, field *ast.Field) (*TypeSchema, error) {
411+
func (parser *Parser) ParseDefinition(typeSpecDef *TypeSpecDef, field *ast.Field, parentSchema *TypeSchema) (*TypeSchema, error) {
411412
typeName := typeSpecDef.FullName()
412413
refTypeName := TypeDocName(typeName, typeSpecDef.TypeSpec)
413414

414-
if parser.isInStructStack(typeSpecDef) {
415-
fmt.Printf("Skipping '%s', recursion detected.", typeName)
416-
schema := &TypeSchema{
415+
if parentSchema != nil && parentSchema.isInTypeChain(typeSpecDef) {
416+
fmt.Printf("Skipping '%s', recursion detected.\n", typeName)
417+
return &TypeSchema{
417418
Name: refTypeName,
418419
FieldName: refTypeName,
419420
FullName: typeName,
420421
Type: OBJECT,
421422
Example: NULL,
422423
PkgPath: typeSpecDef.PkgPath,
423-
}
424-
parser.clearStructStack()
425-
return schema, nil
424+
Parent: parentSchema,
425+
}, nil
426426
}
427427

428428
parser.structStack = append(parser.structStack, typeSpecDef)
@@ -434,35 +434,36 @@ func (parser *Parser) ParseDefinition(typeSpecDef *TypeSpecDef, field *ast.Field
434434
switch expr := typeSpecDef.TypeSpec.Type.(type) {
435435
// type Foo struct {...}
436436
case *ast.StructType:
437-
schema, err := parser.parseStruct(typeSpecDef.File, expr.Fields)
437+
schema, err := parser.parseStruct(typeSpecDef, typeSpecDef.File, expr.Fields, parentSchema)
438438
if err != nil {
439439
return nil, err
440440
}
441441
schema.Name = typeSpecDef.Name()
442442
schema.FullName = typeSpecDef.FullName()
443443
return schema, err
444444
case *ast.Ident:
445-
return parser.getTypeSchema(expr.Name, typeSpecDef.File, field)
445+
return parser.getTypeSchema(expr.Name, typeSpecDef.File, field, parentSchema)
446446
case *ast.MapType:
447447
if keyIdent, ok := expr.Key.(*ast.Ident); ok {
448448
if IsGolangPrimitiveType(keyIdent.Name) {
449449
example := getFieldExample(keyIdent.Name, nil)
450450
if _, ok := expr.Value.(*ast.InterfaceType); ok {
451451
return &TypeSchema{Type: OBJECT, Properties: nil}, nil
452452
}
453-
schema, err := parser.parseTypeExpr(typeSpecDef.File, field, expr.Value)
453+
arrSchama := &TypeSchema{
454+
Name: example,
455+
Type: OBJECT,
456+
FieldName: example,
457+
Parent: parentSchema,
458+
Properties: map[string]*TypeSchema{},
459+
}
460+
schema, err := parser.parseTypeExpr(typeSpecDef.File, field, expr.Value, arrSchama)
454461
if err != nil {
455462
return nil, err
456463
}
457-
return &TypeSchema{
458-
Name: example,
459-
Type: OBJECT,
460-
FieldName: example,
461-
FullName: schema.FullName,
462-
Properties: map[string]*TypeSchema{
463-
strings.Trim(example, "\""): schema,
464-
},
465-
}, err
464+
arrSchama.FullName = schema.FullName
465+
arrSchama.Properties[strings.Trim(example, "\"")] = schema
466+
return arrSchama, nil
466467
}
467468
}
468469

@@ -479,39 +480,40 @@ func (parser *Parser) ParseDefinition(typeSpecDef *TypeSpecDef, field *ast.Field
479480
return &sch, nil
480481
}
481482

482-
func (parser *Parser) parseTypeExpr(file *ast.File, field *ast.Field, typeExpr ast.Expr) (*TypeSchema, error) {
483+
func (parser *Parser) parseTypeExpr(file *ast.File, field *ast.Field, typeExpr ast.Expr, parentSchama *TypeSchema) (*TypeSchema, error) {
483484
switch expr := typeExpr.(type) {
484485
// type Foo interface{}
485486
case *ast.InterfaceType:
486487
return &TypeSchema{
487488
Type: ANY,
488489
Example: "null",
490+
Parent: parentSchama,
489491
}, nil
490492

491493
// type Foo struct {...}
492494
case *ast.StructType:
493-
return parser.parseStruct(file, expr.Fields)
495+
return parser.parseStruct(nil, file, expr.Fields, parentSchama)
494496

495497
// type Foo Baz
496498
case *ast.Ident:
497-
return parser.getTypeSchema(expr.Name, file, field)
499+
return parser.getTypeSchema(expr.Name, file, field, parentSchama)
498500

499501
// type Foo *Baz
500502
case *ast.StarExpr:
501-
return parser.parseTypeExpr(file, field, expr.X)
503+
return parser.parseTypeExpr(file, field, expr.X, parentSchama)
502504

503505
// type Foo pkg.Bar
504506
case *ast.SelectorExpr:
505507
if xIdent, ok := expr.X.(*ast.Ident); ok {
506-
return parser.getTypeSchema(fullTypeName(xIdent.Name, expr.Sel.Name), file, field)
508+
return parser.getTypeSchema(fullTypeName(xIdent.Name, expr.Sel.Name), file, field, parentSchama)
507509
}
508510
// type Foo []Baz
509511
case *ast.ArrayType:
510-
itemSchema, err := parser.parseTypeExpr(file, field, expr.Elt)
512+
itemSchema, err := parser.parseTypeExpr(file, field, expr.Elt, parentSchama)
511513
if err != nil {
512514
return nil, err
513515
}
514-
return &TypeSchema{Type: "array", IsArray: true, ArraySchema: itemSchema}, nil
516+
return &TypeSchema{Type: "array", IsArray: true, ArraySchema: itemSchema, Parent: parentSchama}, nil
515517
// type Foo map[string]Bar
516518
case *ast.MapType:
517519
if keyIdent, ok := expr.Key.(*ast.Ident); ok {
@@ -520,7 +522,7 @@ func (parser *Parser) parseTypeExpr(file *ast.File, field *ast.Field, typeExpr a
520522
if _, ok := expr.Value.(*ast.InterfaceType); ok {
521523
return &TypeSchema{Type: OBJECT, Properties: nil}, nil
522524
}
523-
schema, err := parser.parseTypeExpr(file, field, expr.Value)
525+
schema, err := parser.parseTypeExpr(file, field, expr.Value, parentSchama)
524526
if err != nil {
525527
return nil, err
526528
}
@@ -546,37 +548,38 @@ func (parser *Parser) parseTypeExpr(file *ast.File, field *ast.Field, typeExpr a
546548
return &TypeSchema{Type: OBJECT}, nil
547549
}
548550

549-
func (parser *Parser) parseStruct(file *ast.File, fields *ast.FieldList) (*TypeSchema, error) {
550-
properties := make(map[string]*TypeSchema)
551-
// parser.clearStructStack() //warning
551+
func (parser *Parser) parseStruct(typeSpecDef *TypeSpecDef, file *ast.File, fields *ast.FieldList, parentSchama *TypeSchema) (*TypeSchema, error) {
552+
structSchema := &TypeSchema{
553+
Name: file.Name.Name,
554+
Type: OBJECT,
555+
typeSpecDef: typeSpecDef,
556+
Parent: parentSchama,
557+
Properties: map[string]*TypeSchema{},
558+
}
552559
for _, field := range fields.List {
553560
if len(field.Names) != 1 {
554561
return nil, errors.New("error len(field.Names) != 1")
555562
}
556563
name := field.Names[0].Name
557-
schema, err := parser.parseStructField(file, field)
564+
schema, err := parser.parseStructField(file, field, structSchema)
558565
if err != nil {
559566
return nil, err
560567
}
561568
schema.Name = name
562569
isOmitempty, fieldName := getFieldName(field.Names[0].Name, field, "json")
563570
schema.FieldName = fieldName
564571
schema.IsOmitempty = isOmitempty
565-
properties[schema.FieldName] = schema
572+
structSchema.Properties[schema.FieldName] = schema
566573
}
567-
return &TypeSchema{
568-
Name: file.Name.Name,
569-
Type: OBJECT,
570-
Properties: properties,
571-
}, nil
574+
return structSchema, nil
572575
}
573576

574-
func (parser *Parser) parseStructField(file *ast.File, field *ast.Field) (*TypeSchema, error) {
577+
func (parser *Parser) parseStructField(file *ast.File, field *ast.Field, parentSchama *TypeSchema) (*TypeSchema, error) {
575578
name := field.Names[0].Name
576579
if !ast.IsExported(name) {
577580
return nil, nil
578581
}
579-
return parser.parseTypeExpr(file, field, field.Type)
582+
return parser.parseTypeExpr(file, field, field.Type, parentSchama)
580583
// isArray, typeName, err := getFieldType(field.Type)
581584
// if err != nil {
582585
// return nil, err

0 commit comments

Comments
 (0)