@@ -100,21 +100,34 @@ func (ctx *genKclTypeContext) typeName(defName string, fieldName string, ty type
100
100
return ctx .typeName (defName , fieldName , ty .Elem ())
101
101
case * types.Named :
102
102
obj := ty .Obj ()
103
- switch {
104
- case obj .Pkg ().Path () == "time" && obj .Name () == "Time" :
105
- return typePrimitive (typStr )
106
- case obj .Pkg ().Path () == "time" && obj .Name () == "Duration" :
107
- return typePrimitive (typInt )
108
- case obj .Pkg ().Path () == "math/big" && obj .Name () == "Int" :
109
- return typePrimitive (typInt )
110
- default :
111
- if _ , ok := ctx .goStructs [obj ]; ! ok {
112
- return ctx .typeName (defName , fieldName , ty .Underlying ())
113
- } else {
114
- return typeCustom {
115
- Name : obj .Name (),
103
+ if obj != nil {
104
+ pkg := obj .Pkg ()
105
+ switch {
106
+ case pkg != nil && pkg .Path () == "time" && obj .Name () == "Time" :
107
+ return typePrimitive (typStr )
108
+ case pkg != nil && pkg .Path () == "time" && obj .Name () == "Duration" :
109
+ return typePrimitive (typInt )
110
+ case pkg != nil && pkg .Path () == "math/big" && obj .Name () == "Int" :
111
+ return typePrimitive (typInt )
112
+ default :
113
+ // Struct from external package in the Go module
114
+ if _ , ok := ctx .goStructs [obj ]; ! ok {
115
+ if pkg != nil {
116
+ ty := ctx .typeName (strcase .ToCamel (pkg .Name ()), obj .Name (), ty .Underlying ())
117
+ return ty
118
+ } else {
119
+ ty := ctx .typeName (defName , obj .Name (), ty .Underlying ())
120
+ return ty
121
+ }
122
+ } else {
123
+ // Struct from current package
124
+ return typeCustom {
125
+ Name : obj .Name (),
126
+ }
116
127
}
117
128
}
129
+ } else {
130
+ return typePrimitive (typAny )
118
131
}
119
132
case * types.Array :
120
133
return typeArray {
@@ -137,13 +150,29 @@ func (ctx *genKclTypeContext) typeName(defName string, fieldName string, ty type
137
150
for i := 0 ; i < ty .NumFields (); i ++ {
138
151
sf := ty .Field (i )
139
152
typeName := ctx .typeName (schemaName , sf .Name (), sf .Type ())
153
+ fieldName := formatName (sf .Name ())
154
+ // TODO: get description and tag name from external AST files.
155
+ fieldDescription := ""
156
+ description := ""
157
+ // Use alias name and type defined in the `kcl` or `json`` tag
158
+ tagName , tagTy , err := parserGoStructFieldTag ("" )
159
+ if err == nil {
160
+ if tagName != "" {
161
+ fieldName = tagName
162
+ }
163
+ if tagTy != nil {
164
+ typeName = tagTy
165
+ }
166
+ }
167
+ result .schema .Description = description
140
168
result .schema .Name = schemaName
141
169
result .schema .Properties = append (result .Properties , property {
142
- Name : formatName (sf .Name ()),
143
- Type : typeName ,
170
+ Name : fieldName ,
171
+ Type : typeName ,
172
+ Description : fieldDescription ,
144
173
})
145
- ctx .resultMap [schemaName ] = result
146
174
}
175
+ ctx .resultMap [schemaName ] = result
147
176
}
148
177
return typeCustom {
149
178
Name : schemaName ,
@@ -185,13 +214,19 @@ func (ctx *genKclTypeContext) convertSchemaFromGoPackage() ([]convertResult, err
185
214
result := convertResult {IsSchema : true }
186
215
result .schema .Name = name
187
216
result .schema .Description = s .doc
217
+ ctx .resultMap [name ] = result
188
218
for _ , field := range s .fields {
189
219
typeName := ctx .typeName (name , field .name , field .ty )
190
220
fieldName := formatName (field .name )
221
+ // Use alias name and type defined in the `kcl` or `json`` tag
191
222
tagName , tagTy , err := parserGoStructFieldTag (field .tag )
192
- if err == nil && tagName != "" && tagTy != nil {
193
- fieldName = tagName
194
- typeName = tagTy
223
+ if err == nil {
224
+ if tagName != "" {
225
+ fieldName = tagName
226
+ }
227
+ if tagTy != nil {
228
+ typeName = tagTy
229
+ }
195
230
}
196
231
result .schema .Properties = append (result .Properties , property {
197
232
Name : fieldName ,
@@ -219,24 +254,28 @@ func fetchStructs(pkgPath string) (map[*types.TypeName]goStruct, error) {
219
254
}
220
255
structs := make (map [* types.TypeName ]goStruct )
221
256
for _ , pkg := range pkgs {
257
+ if len (pkg .Errors ) > 0 {
258
+ return nil , errors .New (pkg .Errors [0 ].Error ())
259
+ }
222
260
astFiles := pkg .Syntax
223
261
scope := pkg .Types .Scope ()
224
262
for _ , name := range scope .Names () {
225
263
obj := scope .Lookup (name )
226
264
if obj , ok := obj .(* types.TypeName ); ok {
227
- named , _ := obj .Type ().(* types.Named )
228
- if structType , ok := named .Underlying ().(* types.Struct ); ok {
229
- structDoc := getStructDoc (name , astFiles )
230
- fields , fieldDocs := getStructFieldsAndDocs (structType , name , astFiles )
231
- pkgPath := named .Obj ().Pkg ().Path ()
232
- pkgName := named .Obj ().Pkg ().Name ()
233
- structs [named .Obj ()] = goStruct {
234
- pkgPath : pkgPath ,
235
- pkgName : pkgName ,
236
- name : name ,
237
- fields : fields ,
238
- doc : structDoc ,
239
- fieldDocs : fieldDocs ,
265
+ if named , ok := obj .Type ().(* types.Named ); ok {
266
+ if structType , ok := named .Underlying ().(* types.Struct ); ok {
267
+ structDoc := getStructDoc (name , astFiles )
268
+ pkgPath := named .Obj ().Pkg ().Path ()
269
+ pkgName := named .Obj ().Pkg ().Name ()
270
+ fields , fieldDocs := getStructFieldsAndDocs (structType , pkgName , name , astFiles )
271
+ structs [named .Obj ()] = goStruct {
272
+ pkgPath : pkgPath ,
273
+ pkgName : pkgName ,
274
+ name : name ,
275
+ fields : fields ,
276
+ doc : structDoc ,
277
+ fieldDocs : fieldDocs ,
278
+ }
240
279
}
241
280
}
242
281
}
@@ -262,26 +301,28 @@ func getStructDoc(structName string, astFiles []*ast.File) string {
262
301
return ""
263
302
}
264
303
265
- func getStructFieldsAndDocs (structType * types.Struct , structName string , astFiles []* ast.File ) ([]field , map [string ]string ) {
304
+ func getStructFieldsAndDocs (structType * types.Struct , pkgName string , structName string , astFiles []* ast.File ) ([]field , map [string ]string ) {
266
305
fieldDocs := make (map [string ]string )
267
306
var fields []field
268
307
for i := 0 ; i < structType .NumFields (); i ++ {
269
308
f := structType .Field (i )
270
309
var tag string
271
310
for _ , file := range astFiles {
272
- for _ , decl := range file .Decls {
273
- if genDecl , ok := decl .(* ast.GenDecl ); ok && genDecl .Tok == token .TYPE {
274
- for _ , spec := range genDecl .Specs {
275
- if typeSpec , ok := spec .(* ast.TypeSpec ); ok && typeSpec .Name .Name == structName {
276
- if structType , ok := typeSpec .Type .(* ast.StructType ); ok {
277
- for _ , field := range structType .Fields .List {
278
- for _ , fieldName := range field .Names {
279
- if fieldName .Name == f .Name () {
280
- if field .Doc != nil {
281
- fieldDocs [fieldName .Name ] = field .Doc .Text ()
282
- }
283
- if field .Tag != nil {
284
- tag = field .Tag .Value
311
+ if pkgName == "" || file .Name .Name == pkgName {
312
+ for _ , decl := range file .Decls {
313
+ if genDecl , ok := decl .(* ast.GenDecl ); ok && genDecl .Tok == token .TYPE {
314
+ for _ , spec := range genDecl .Specs {
315
+ if typeSpec , ok := spec .(* ast.TypeSpec ); ok && typeSpec .Name .Name == structName {
316
+ if structType , ok := typeSpec .Type .(* ast.StructType ); ok {
317
+ for _ , field := range structType .Fields .List {
318
+ for _ , fieldName := range field .Names {
319
+ if fieldName .Name == f .Name () {
320
+ if field .Doc != nil {
321
+ fieldDocs [fieldName .Name ] = field .Doc .Text ()
322
+ }
323
+ if field .Tag != nil {
324
+ tag = field .Tag .Value
325
+ }
285
326
}
286
327
}
287
328
}
@@ -293,7 +334,7 @@ func getStructFieldsAndDocs(structType *types.Struct, structName string, astFile
293
334
}
294
335
}
295
336
if f .Embedded () {
296
- embeddedFields , embeddedFieldDocs := getEmbeddedFieldsAndDocs (f .Type (), astFiles , structName )
337
+ embeddedFields , embeddedFieldDocs := getEmbeddedFieldsAndDocs (f .Type (), astFiles , "" , structName )
297
338
fields = append (fields , embeddedFields ... )
298
339
for k , v := range embeddedFieldDocs {
299
340
fieldDocs [k ] = v
@@ -311,18 +352,18 @@ func getStructFieldsAndDocs(structType *types.Struct, structName string, astFile
311
352
return fields , fieldDocs
312
353
}
313
354
314
- func getEmbeddedFieldsAndDocs (t types.Type , astFiles []* ast.File , structName string ) ([]field , map [string ]string ) {
355
+ func getEmbeddedFieldsAndDocs (t types.Type , astFiles []* ast.File , pkgName , structName string ) ([]field , map [string ]string ) {
315
356
fieldDocs := make (map [string ]string )
316
357
var fields []field
317
358
switch t := t .(type ) {
318
359
case * types.Pointer :
319
- fields , fieldDocs = getEmbeddedFieldsAndDocs (t .Elem (), astFiles , structName )
360
+ fields , fieldDocs = getEmbeddedFieldsAndDocs (t .Elem (), astFiles , pkgName , structName )
320
361
case * types.Named :
321
362
if structType , ok := t .Underlying ().(* types.Struct ); ok {
322
- fields , fieldDocs = getStructFieldsAndDocs (structType , structName , astFiles )
363
+ fields , fieldDocs = getStructFieldsAndDocs (structType , pkgName , structName , astFiles )
323
364
}
324
365
case * types.Struct :
325
- fields , fieldDocs = getStructFieldsAndDocs (t , structName , astFiles )
366
+ fields , fieldDocs = getStructFieldsAndDocs (t , pkgName , structName , astFiles )
326
367
}
327
368
return fields , fieldDocs
328
369
}
@@ -335,7 +376,16 @@ func parserGoStructFieldTag(tag string) (string, typeInterface, error) {
335
376
}
336
377
value , ok := lookupTag (sp [1 ], "kcl" )
337
378
if ! ok {
338
- return "" , nil , errors .New ("not found tag key named kcl" )
379
+ value , ok = lookupTag (sp [1 ], "json" )
380
+ if ! ok {
381
+ return "" , nil , errors .New ("not found tag key named json or kcl" )
382
+ }
383
+ tagInfos := strings .Split (value , "," )
384
+ if len (tagInfos ) > 0 {
385
+ return tagInfos [0 ], nil , nil
386
+ } else {
387
+ return "" , nil , errors .New ("invalid tag key named json" )
388
+ }
339
389
}
340
390
reg := "name=.*,type=.*"
341
391
match , err := regexp .Match (reg , []byte (value ))
0 commit comments