@@ -100,21 +100,34 @@ func (ctx *genKclTypeContext) typeName(defName string, fieldName string, ty type
100100 return ctx .typeName (defName , fieldName , ty .Elem ())
101101 case * types.Named :
102102 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+ }
116127 }
117128 }
129+ } else {
130+ return typePrimitive (typAny )
118131 }
119132 case * types.Array :
120133 return typeArray {
@@ -137,13 +150,29 @@ func (ctx *genKclTypeContext) typeName(defName string, fieldName string, ty type
137150 for i := 0 ; i < ty .NumFields (); i ++ {
138151 sf := ty .Field (i )
139152 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
140168 result .schema .Name = schemaName
141169 result .schema .Properties = append (result .Properties , property {
142- Name : formatName (sf .Name ()),
143- Type : typeName ,
170+ Name : fieldName ,
171+ Type : typeName ,
172+ Description : fieldDescription ,
144173 })
145- ctx .resultMap [schemaName ] = result
146174 }
175+ ctx .resultMap [schemaName ] = result
147176 }
148177 return typeCustom {
149178 Name : schemaName ,
@@ -185,13 +214,19 @@ func (ctx *genKclTypeContext) convertSchemaFromGoPackage() ([]convertResult, err
185214 result := convertResult {IsSchema : true }
186215 result .schema .Name = name
187216 result .schema .Description = s .doc
217+ ctx .resultMap [name ] = result
188218 for _ , field := range s .fields {
189219 typeName := ctx .typeName (name , field .name , field .ty )
190220 fieldName := formatName (field .name )
221+ // Use alias name and type defined in the `kcl` or `json`` tag
191222 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+ }
195230 }
196231 result .schema .Properties = append (result .Properties , property {
197232 Name : fieldName ,
@@ -219,24 +254,28 @@ func fetchStructs(pkgPath string) (map[*types.TypeName]goStruct, error) {
219254 }
220255 structs := make (map [* types.TypeName ]goStruct )
221256 for _ , pkg := range pkgs {
257+ if len (pkg .Errors ) > 0 {
258+ return nil , errors .New (pkg .Errors [0 ].Error ())
259+ }
222260 astFiles := pkg .Syntax
223261 scope := pkg .Types .Scope ()
224262 for _ , name := range scope .Names () {
225263 obj := scope .Lookup (name )
226264 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+ }
240279 }
241280 }
242281 }
@@ -262,26 +301,28 @@ func getStructDoc(structName string, astFiles []*ast.File) string {
262301 return ""
263302}
264303
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 ) {
266305 fieldDocs := make (map [string ]string )
267306 var fields []field
268307 for i := 0 ; i < structType .NumFields (); i ++ {
269308 f := structType .Field (i )
270309 var tag string
271310 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+ }
285326 }
286327 }
287328 }
@@ -293,7 +334,7 @@ func getStructFieldsAndDocs(structType *types.Struct, structName string, astFile
293334 }
294335 }
295336 if f .Embedded () {
296- embeddedFields , embeddedFieldDocs := getEmbeddedFieldsAndDocs (f .Type (), astFiles , structName )
337+ embeddedFields , embeddedFieldDocs := getEmbeddedFieldsAndDocs (f .Type (), astFiles , "" , structName )
297338 fields = append (fields , embeddedFields ... )
298339 for k , v := range embeddedFieldDocs {
299340 fieldDocs [k ] = v
@@ -311,18 +352,18 @@ func getStructFieldsAndDocs(structType *types.Struct, structName string, astFile
311352 return fields , fieldDocs
312353}
313354
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 ) {
315356 fieldDocs := make (map [string ]string )
316357 var fields []field
317358 switch t := t .(type ) {
318359 case * types.Pointer :
319- fields , fieldDocs = getEmbeddedFieldsAndDocs (t .Elem (), astFiles , structName )
360+ fields , fieldDocs = getEmbeddedFieldsAndDocs (t .Elem (), astFiles , pkgName , structName )
320361 case * types.Named :
321362 if structType , ok := t .Underlying ().(* types.Struct ); ok {
322- fields , fieldDocs = getStructFieldsAndDocs (structType , structName , astFiles )
363+ fields , fieldDocs = getStructFieldsAndDocs (structType , pkgName , structName , astFiles )
323364 }
324365 case * types.Struct :
325- fields , fieldDocs = getStructFieldsAndDocs (t , structName , astFiles )
366+ fields , fieldDocs = getStructFieldsAndDocs (t , pkgName , structName , astFiles )
326367 }
327368 return fields , fieldDocs
328369}
@@ -335,7 +376,16 @@ func parserGoStructFieldTag(tag string) (string, typeInterface, error) {
335376 }
336377 value , ok := lookupTag (sp [1 ], "kcl" )
337378 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+ }
339389 }
340390 reg := "name=.*,type=.*"
341391 match , err := regexp .Match (reg , []byte (value ))
0 commit comments