swagger.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "go/ast"
  6. "go/parser"
  7. "go/token"
  8. "go/types"
  9. "io"
  10. "log"
  11. "os"
  12. "reflect"
  13. "strconv"
  14. "strings"
  15. "golang.org/x/tools/go/ast/astutil"
  16. "golang.org/x/tools/go/packages"
  17. "gopkg.in/yaml.v3"
  18. )
  19. var swagger = map[string]interface{}{
  20. "openapi": "3.0.0",
  21. "info": map[string]string{
  22. "title": "CRM",
  23. "description": "CRM",
  24. "version": "0.0.1",
  25. },
  26. "paths": map[string]interface{}{},
  27. "security": []map[string]interface{}{
  28. {
  29. "bearerAuth": []interface{}{},
  30. },
  31. },
  32. "components": map[string]interface{}{
  33. "securitySchemes": map[string]interface{}{
  34. "basicAuth": map[string]interface{}{
  35. "type": "http",
  36. "scheme": "basic",
  37. },
  38. "bearerAuth": map[string]interface{}{
  39. "type": "http",
  40. "scheme": "bearer",
  41. },
  42. },
  43. "schemas": map[string]interface{}{},
  44. "examples": map[string]interface{}{
  45. "success": map[string]interface{}{
  46. "summary": "请求成功",
  47. "value": map[string]interface{}{
  48. "code": 200,
  49. "msg": "success",
  50. },
  51. },
  52. },
  53. },
  54. }
  55. type pathModel struct {
  56. OperationId string
  57. Summary string
  58. Tags []string
  59. Request string
  60. }
  61. func newPath(m pathModel) interface{} {
  62. schemaref := fmt.Sprintf("#/components/schemas/%s", m.Request)
  63. examplesref := fmt.Sprintf("#/components/examples/%s", m.Request)
  64. return map[string]interface{}{
  65. "post": map[string]interface{}{
  66. "tags": m.Tags,
  67. "operationId": m.OperationId,
  68. "summary": m.Summary,
  69. "requestBody": map[string]interface{}{
  70. "required": true,
  71. "content": map[string]interface{}{
  72. "application/json": map[string]interface{}{
  73. "schema": map[string]interface{}{
  74. "oneOf": []map[string]interface{}{
  75. {
  76. "$ref": schemaref,
  77. },
  78. },
  79. },
  80. "examples": map[string]interface{}{
  81. m.Request: map[string]interface{}{
  82. "$ref": examplesref,
  83. },
  84. },
  85. },
  86. },
  87. "responses": map[string]interface{}{
  88. "200": map[string]interface{}{
  89. "description": "请求成功",
  90. "content": map[string]interface{}{
  91. "application/json": map[string]interface{}{
  92. "examples": map[string]interface{}{
  93. "success": map[string]interface{}{
  94. "$ref": "#/components/examples/success",
  95. },
  96. },
  97. },
  98. },
  99. },
  100. },
  101. },
  102. },
  103. }
  104. }
  105. func testGoParser() error {
  106. sourceFile, err := os.Open("/home/lai/code/working/opms_backend/opms_parent/app/handler/contract/ctr_contract.go")
  107. if err != nil {
  108. return err
  109. }
  110. sourceContent, err := io.ReadAll(sourceFile)
  111. if err != nil {
  112. return err
  113. }
  114. // Create the AST by parsing src.
  115. fset := token.NewFileSet() // positions are relative to fset
  116. f, err := parser.ParseFile(fset, "", sourceContent, parser.ParseComments)
  117. if err != nil {
  118. panic(err)
  119. }
  120. // Print the imports from the file's AST.
  121. for _, s := range f.Imports {
  122. debugLog(s.Path.Value)
  123. fmt.Printf("%#v\n", s.Path)
  124. }
  125. debugLog("-----------------------")
  126. if Debug {
  127. ast.Print(fset, f)
  128. }
  129. debugLog("-----------------------")
  130. for _, c := range f.Comments {
  131. for _, l := range c.List {
  132. fmt.Printf("%#v%#v\n", l.Text, l.Slash)
  133. }
  134. }
  135. return nil
  136. }
  137. type SwaggerModel struct {
  138. Type string `yaml:"type"`
  139. Description string `yaml:"description"`
  140. Properties map[string]*SwaggerModel `yaml:"properties,omitempty"`
  141. Items *SwaggerModel `yaml:"items,omitempty"`
  142. Ref string `yaml:"ref,omitempty"`
  143. }
  144. func RangeSwaggerModel(node *SwaggerModel) []*SwaggerModel {
  145. if node == nil {
  146. return nil
  147. }
  148. allnode := []*SwaggerModel{}
  149. nodes := []*SwaggerModel{node}
  150. for len(nodes) != 0 {
  151. newnode := []*SwaggerModel{}
  152. for _, n := range nodes {
  153. allnode = append(allnode, n)
  154. if n.Items != nil {
  155. newnode = append(newnode, n.Items)
  156. }
  157. for _, p := range n.Properties {
  158. newnode = append(newnode, p)
  159. }
  160. }
  161. nodes = newnode
  162. }
  163. return allnode
  164. }
  165. const pkgLoadMode = packages.NeedName | packages.NeedFiles | packages.NeedImports | packages.NeedDeps | packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo
  166. var AllPackages = map[string]*packages.Package{}
  167. var Models = map[*ast.Ident]*entityDecl{}
  168. var AllStructModel = map[string]*SwaggerModel{}
  169. var AllSwaggerModel = map[string]*SwaggerModel{}
  170. var SpecifiedSwaggerModel = []map[string]string{}
  171. var Routes = map[string]pathModel{}
  172. type entityDecl struct {
  173. Type *types.Named
  174. File *ast.File
  175. Pkg *packages.Package
  176. }
  177. var outfile string
  178. func init() {
  179. flag.StringVar(&outfile, "o", "swagger.yml", "output file")
  180. }
  181. func main() {
  182. // testGoParser()
  183. // return
  184. flag.Parse()
  185. toload := []string{"dashoo.cn/micro/app/model/contract", "dashoo.cn/micro/app/handler/contract"}
  186. cfg := &packages.Config{Mode: pkgLoadMode}
  187. pkgs, err := packages.Load(cfg, toload...)
  188. if err != nil {
  189. fmt.Fprintf(os.Stderr, "load: %v\n", err)
  190. os.Exit(1)
  191. }
  192. if packages.PrintErrors(pkgs) > 0 {
  193. os.Exit(1)
  194. }
  195. for _, pkg := range pkgs {
  196. AllPackages[pkg.PkgPath] = pkg
  197. for _, file := range pkg.Syntax {
  198. for _, dt := range file.Decls {
  199. switch fd := dt.(type) {
  200. case *ast.GenDecl:
  201. for _, sp := range fd.Specs {
  202. switch ts := sp.(type) {
  203. case *ast.TypeSpec:
  204. def, ok := pkg.TypesInfo.Defs[ts.Name]
  205. if !ok {
  206. debugLog("couldn't find type info for %s", ts.Name)
  207. continue
  208. }
  209. nt, isNamed := def.Type().(*types.Named)
  210. if !isNamed {
  211. debugLog("%s is not a named type but a %T", ts.Name, def.Type())
  212. continue
  213. }
  214. key := ts.Name
  215. Models[key] = &entityDecl{
  216. Type: nt,
  217. File: file,
  218. Pkg: pkg,
  219. }
  220. }
  221. }
  222. }
  223. }
  224. }
  225. }
  226. // Print the names of the source files
  227. // for each package listed on the command line.
  228. for _, pkg := range pkgs {
  229. debugLog("-----------%s", pkg.Name)
  230. for _, f := range pkg.Syntax {
  231. detectModels(pkg, f)
  232. }
  233. }
  234. for n := range AllStructModel {
  235. m := AllStructModel[n]
  236. if m == nil {
  237. continue
  238. }
  239. // fmt.Println(m.Ref, AllStructModel[m.Ref])
  240. for _, subm := range RangeSwaggerModel(m) {
  241. if subm.Ref != "" && AllStructModel[subm.Ref] != nil {
  242. subm.Items = AllStructModel[subm.Ref].Items
  243. subm.Properties = AllStructModel[subm.Ref].Properties
  244. }
  245. }
  246. // b, err := yaml.Marshal(m)
  247. // if err != nil {
  248. // panic(err)
  249. // }
  250. // fmt.Println(n)
  251. // fmt.Println(string(b))
  252. }
  253. genconfig(outfile)
  254. }
  255. func genconfig(filename string) {
  256. f, err := os.Create(filename)
  257. if err != nil {
  258. panic(err)
  259. }
  260. defer f.Close()
  261. for n := range AllStructModel {
  262. m := AllStructModel[n]
  263. if m == nil {
  264. continue
  265. }
  266. namelist := strings.Split(n, ".")
  267. name := namelist[len(namelist)-1]
  268. swagger["components"].(map[string]interface{})["schemas"].(map[string]interface{})[name] = m
  269. swagger["components"].(map[string]interface{})["examples"].(map[string]interface{})[name] = map[string]interface{}{
  270. "value": map[string]interface{}{
  271. "placeholder": "",
  272. },
  273. }
  274. }
  275. for p, m := range Routes {
  276. swagger["paths"].(map[string]interface{})[p] = newPath(m)
  277. }
  278. encoder := yaml.NewEncoder(f)
  279. encoder.SetIndent(2)
  280. err = encoder.Encode(swagger)
  281. if err != nil {
  282. panic(err)
  283. }
  284. }
  285. func getFuncRecv(fd *ast.FuncDecl) string {
  286. defer func() {
  287. if r := recover(); r != nil {
  288. debugLog("%s", r)
  289. }
  290. }()
  291. return fd.Recv.List[0].Type.(*ast.StarExpr).X.(*ast.Ident).Name
  292. }
  293. func getFuncParams(fd *ast.FuncDecl) string {
  294. defer func() {
  295. if r := recover(); r != nil {
  296. debugLog("%s", r)
  297. }
  298. }()
  299. return fd.Type.Params.List[1].Type.(*ast.StarExpr).X.(*ast.SelectorExpr).Sel.Name
  300. }
  301. func detectPath(fd *ast.FuncDecl) {
  302. recv := getFuncRecv(fd)
  303. fname := fd.Name.String()
  304. req := getFuncParams(fd)
  305. debugLog("//////////%v %s %s %s %s", fd, fname, recv, req, fd.Doc.Text())
  306. commentText := fd.Doc.Text()
  307. for _, c := range strings.Split(commentText, "\n") {
  308. if !strings.HasPrefix(c, "swagger:route") {
  309. continue
  310. }
  311. names := strings.Split(c, " ")
  312. tags := []string{}
  313. summary := ""
  314. if len(names) == 3 {
  315. tags = strings.Split(names[1], ",")
  316. summary = names[2]
  317. }
  318. path := fmt.Sprintf("/%s.%s", recv, fname)
  319. operationId := recv + fname
  320. Routes[path] = pathModel{
  321. OperationId: operationId,
  322. Summary: summary,
  323. Tags: tags,
  324. Request: req,
  325. }
  326. break
  327. }
  328. }
  329. func detectModels(pkg *packages.Package, file *ast.File) {
  330. for _, dt := range file.Decls {
  331. switch fd := dt.(type) {
  332. case *ast.BadDecl:
  333. continue
  334. case *ast.FuncDecl:
  335. detectPath(fd)
  336. case *ast.GenDecl:
  337. processDecl(pkg, file, fd)
  338. }
  339. }
  340. }
  341. func processDecl(pkg *packages.Package, file *ast.File, gd *ast.GenDecl) error {
  342. for _, sp := range gd.Specs {
  343. switch ts := sp.(type) {
  344. case *ast.ValueSpec:
  345. return nil
  346. case *ast.ImportSpec:
  347. return nil
  348. case *ast.TypeSpec:
  349. def, ok := pkg.TypesInfo.Defs[ts.Name]
  350. if !ok {
  351. debugLog("couldn't find type info for %s", ts.Name)
  352. continue
  353. }
  354. nt, isNamed := def.Type().(*types.Named)
  355. if !isNamed {
  356. debugLog("%s is not a named type but a %T", ts.Name, def.Type())
  357. continue
  358. }
  359. comments := ts.Doc // type ( /* doc */ Foo struct{} )
  360. if comments == nil {
  361. comments = gd.Doc // /* doc */ type ( Foo struct{} )
  362. }
  363. // decl := &entityDecl{
  364. // Comments: comments,
  365. // Type: nt,
  366. // Ident: ts.Name,
  367. // Spec: ts,
  368. // File: file,
  369. // Pkg: pkg,
  370. // }
  371. // key := ts.Name
  372. // if n&modelNode != 0 && decl.HasModelAnnotation() {
  373. // a.Models[key] = decl
  374. // }
  375. // if n&parametersNode != 0 && decl.HasParameterAnnotation() {
  376. // a.Parameters = append(a.Parameters, decl)
  377. // }
  378. // if n&responseNode != 0 && decl.HasResponseAnnotation() {
  379. // a.Responses = append(a.Responses, decl)
  380. // }
  381. switch tpe := nt.Obj().Type().(type) {
  382. case *types.Struct:
  383. st := tpe
  384. for i := 0; i < st.NumFields(); i++ {
  385. fld := st.Field(i)
  386. if !fld.Anonymous() {
  387. debugLog("skipping field %q for allOf scan because not anonymous\n", fld.Name())
  388. continue
  389. }
  390. tg := st.Tag(i)
  391. debugLog(fld.Name(), tg)
  392. }
  393. case *types.Slice:
  394. debugLog("Slice")
  395. case *types.Basic:
  396. debugLog("Basic")
  397. case *types.Interface:
  398. debugLog("Interface")
  399. case *types.Array:
  400. debugLog("Array")
  401. case *types.Map:
  402. debugLog("Map")
  403. case *types.Named:
  404. debugLog("Named")
  405. o := tpe.Obj()
  406. if o != nil {
  407. debugLog("got the named type object: %s.%s | isAlias: %t | exported: %t //////////// %s", o.Pkg().Path(), o.Name(), o.IsAlias(), o.Exported(), comments.Text())
  408. if o.Pkg().Name() == "time" && o.Name() == "Time" {
  409. // schema.Typed("string", "date-time")
  410. return nil
  411. }
  412. for {
  413. ti := pkg.TypesInfo.Types[ts.Type]
  414. if ti.IsBuiltin() {
  415. break
  416. }
  417. if ti.IsType() {
  418. err, ret := buildFromType(ti.Type, file, comments.Text())
  419. if err != nil {
  420. return err
  421. }
  422. AllStructModel[fmt.Sprintf("%s.%s", o.Pkg().Path(), o.Name())] = ret
  423. break
  424. }
  425. }
  426. }
  427. }
  428. }
  429. }
  430. return nil
  431. }
  432. func buildFromType(tpe types.Type, declFile *ast.File, desc string) (error, *SwaggerModel) {
  433. switch titpe := tpe.(type) {
  434. case *types.Basic:
  435. return nil, &SwaggerModel{
  436. Type: swaggerSchemaForType(titpe.String()),
  437. Description: desc,
  438. }
  439. case *types.Pointer:
  440. return buildFromType(titpe.Elem(), declFile, desc)
  441. case *types.Struct:
  442. return buildFromStruct(declFile, titpe, desc)
  443. case *types.Slice:
  444. err, ret := buildFromType(titpe.Elem(), declFile, desc)
  445. if err != nil {
  446. return err, nil
  447. }
  448. return nil, &SwaggerModel{
  449. Type: "array",
  450. Items: ret,
  451. Description: desc,
  452. }
  453. case *types.Named:
  454. tio := titpe.Obj()
  455. debugLog("%s", tio)
  456. if tio.Pkg() == nil && tio.Name() == "error" {
  457. return nil, &SwaggerModel{
  458. Type: swaggerSchemaForType(tio.Name()),
  459. Description: desc,
  460. }
  461. }
  462. if tpe.String() == "github.com/gogf/gf/os/gtime.Time" {
  463. return nil, &SwaggerModel{
  464. Type: "string",
  465. Description: desc + "DATETIME",
  466. }
  467. }
  468. debugLog("named refined type %s.%s", tio.Pkg().Path(), tio.Name())
  469. pkg, found := PkgForType(tpe)
  470. if !found {
  471. // this must be a builtin
  472. debugLog("skipping because package is nil: %s", tpe.String())
  473. return nil, nil
  474. }
  475. if pkg.Name == "time" && tio.Name() == "Time" {
  476. return nil, &SwaggerModel{
  477. Type: "string",
  478. Description: desc,
  479. }
  480. }
  481. switch utitpe := tpe.Underlying().(type) {
  482. case *types.Struct:
  483. if decl, ok := FindModel(tio.Pkg().Path(), tio.Name()); ok {
  484. if decl.Type.Obj().Pkg().Path() == "time" && decl.Type.Obj().Name() == "Time" {
  485. return nil, &SwaggerModel{
  486. Type: "string",
  487. Description: desc,
  488. }
  489. }
  490. debugLog("!!!!!!!%s", decl.Type.String())
  491. return nil, &SwaggerModel{
  492. Type: "object",
  493. Ref: decl.Type.String(),
  494. }
  495. }
  496. case *types.Slice:
  497. debugLog("!!!!!!!slice %s", utitpe.Elem())
  498. // decl, ok := FindModel(tio.Pkg().Path(), tio.Name())
  499. // return buildFromType(utitpe.Elem(), tgt.Items())
  500. }
  501. default:
  502. panic(fmt.Sprintf("WARNING: can't determine refined type %s (%T)", titpe.String(), titpe))
  503. }
  504. return nil, nil
  505. }
  506. func buildFromStruct(declFile *ast.File, st *types.Struct, desc string) (error, *SwaggerModel) {
  507. // for i := 0; i < st.NumFields(); i++ {
  508. // fld := st.Field(i)
  509. // if !fld.Anonymous() {
  510. // debugLog("skipping field %q for allOf scan because not anonymous", fld.Name())
  511. // continue
  512. // }
  513. // tg := st.Tag(i)
  514. // debugLog("maybe allof field(%t) %s: %s (%T) [%q](anon: %t, embedded: %t)", fld.IsField(), fld.Name(), fld.Type().String(), fld.Type(), tg, fld.Anonymous(), fld.Embedded())
  515. // var afld *ast.Field
  516. // ans, _ := astutil.PathEnclosingInterval(declFile, fld.Pos(), fld.Pos())
  517. // // debugLog("got %d nodes (exact: %t)", len(ans), isExact)
  518. // for _, an := range ans {
  519. // at, valid := an.(*ast.Field)
  520. // if !valid {
  521. // continue
  522. // }
  523. // debugLog("maybe allof field %s: %s(%T) [%q]", fld.Name(), fld.Type().String(), fld.Type(), tg)
  524. // afld = at
  525. // break
  526. // }
  527. // if afld == nil {
  528. // debugLog("can't find source associated with %s for %s", fld.String(), st.String())
  529. // continue
  530. // }
  531. // _, ignore, _, err := parseJSONTag(afld)
  532. // if err != nil {
  533. // return err
  534. // }
  535. // if ignore {
  536. // continue
  537. // }
  538. // }
  539. properties := map[string]*SwaggerModel{}
  540. for i := 0; i < st.NumFields(); i++ {
  541. fld := st.Field(i)
  542. tg := st.Tag(i)
  543. if fld.Embedded() {
  544. if fld.Name() == "PageReq" {
  545. properties["beginTime"] = &SwaggerModel{Type: "string", Description: "开始时间"}
  546. properties["endTime"] = &SwaggerModel{Type: "string", Description: "结束时间"}
  547. properties["pageNum"] = &SwaggerModel{Type: "int", Description: "当前页码"}
  548. properties["pageSize"] = &SwaggerModel{Type: "int", Description: "每页数"}
  549. properties["orderBy"] = &SwaggerModel{Type: "string", Description: "排序方式"}
  550. }
  551. debugLog("Embedded %s, %s", fld.Name(), fld.Pkg())
  552. continue
  553. }
  554. if !fld.Exported() {
  555. debugLog("skipping field %s because it's not exported", fld.Name())
  556. continue
  557. }
  558. var afld *ast.Field
  559. ans, _ := astutil.PathEnclosingInterval(declFile, fld.Pos(), fld.Pos())
  560. // debugLog("got %d nodes (exact: %t)", len(ans), isExact)
  561. for _, an := range ans {
  562. at, valid := an.(*ast.Field)
  563. if !valid {
  564. continue
  565. }
  566. debugLog("field %s: %s(%T) [%q] ==> %s", fld.Name(), fld.Type().String(), fld.Type(), tg, at.Doc.Text())
  567. afld = at
  568. break
  569. }
  570. if afld == nil {
  571. debugLog("can't find source associated with %s", fld.String())
  572. continue
  573. }
  574. name, _, isString, err := parseJSONTag(afld)
  575. if err != nil {
  576. return err, nil
  577. }
  578. commentText := ""
  579. if afld.Comment != nil {
  580. commentText = afld.Comment.Text()
  581. }
  582. err, ret := buildFromType(fld.Type(), declFile, commentText)
  583. if err != nil {
  584. return err, nil
  585. }
  586. debugLog("****** %s %v %s", fld.Type(), ret, commentText)
  587. if isString {
  588. return nil, &SwaggerModel{
  589. Type: "string",
  590. Description: desc,
  591. }
  592. }
  593. properties[name] = ret
  594. }
  595. return nil, &SwaggerModel{
  596. Type: "object",
  597. Properties: properties,
  598. Description: desc,
  599. }
  600. }
  601. func swaggerSchemaForType(typeName string) string {
  602. switch typeName {
  603. case "bool":
  604. return "boolean"
  605. case "byte":
  606. return "integer"
  607. case "float32":
  608. return "number"
  609. case "float64":
  610. return "number"
  611. case "int":
  612. return "integer"
  613. case "int16":
  614. return "integer"
  615. case "int32":
  616. return "integer"
  617. case "int64":
  618. return "integer"
  619. case "int8":
  620. return "integer"
  621. case "rune":
  622. return "integer"
  623. case "string":
  624. return "string"
  625. case "uint":
  626. return "integer"
  627. case "uint16":
  628. return "integer"
  629. case "uint32":
  630. return "integer"
  631. case "uint64":
  632. return "integer"
  633. case "uint8":
  634. return "integer"
  635. }
  636. return ""
  637. }
  638. func FindModel(pkgPath, name string) (*entityDecl, bool) {
  639. for _, cand := range Models {
  640. ct := cand.Type.Obj()
  641. if ct.Name() == name && ct.Pkg().Path() == pkgPath {
  642. return cand, true
  643. }
  644. }
  645. return nil, false
  646. }
  647. func PkgForType(t types.Type) (*packages.Package, bool) {
  648. switch tpe := t.(type) {
  649. // case *types.Basic:
  650. // case *types.Struct:
  651. // case *types.Pointer:
  652. // case *types.Interface:
  653. // case *types.Array:
  654. // case *types.Slice:
  655. // case *types.Map:
  656. case *types.Named:
  657. v, ok := AllPackages[tpe.Obj().Pkg().Path()]
  658. return v, ok
  659. default:
  660. log.Printf("unknown type to find the package for [%T]: %s", t, t.String())
  661. return nil, false
  662. }
  663. }
  664. func parseJSONTag(field *ast.Field) (name string, ignore bool, isString bool, err error) {
  665. if len(field.Names) > 0 {
  666. name = field.Names[0].Name
  667. }
  668. if field.Tag == nil || len(strings.TrimSpace(field.Tag.Value)) == 0 {
  669. return name, false, false, nil
  670. }
  671. tv, err := strconv.Unquote(field.Tag.Value)
  672. if err != nil {
  673. return name, false, false, err
  674. }
  675. if strings.TrimSpace(tv) != "" {
  676. st := reflect.StructTag(tv)
  677. jsonParts := tagOptions(strings.Split(st.Get("json"), ","))
  678. if jsonParts.Contain("string") {
  679. // Need to check if the field type is a scalar. Otherwise, the
  680. // ",string" directive doesn't apply.
  681. isString = isFieldStringable(field.Type)
  682. }
  683. switch jsonParts.Name() {
  684. case "-":
  685. return name, true, isString, nil
  686. case "":
  687. return name, false, isString, nil
  688. default:
  689. return jsonParts.Name(), false, isString, nil
  690. }
  691. }
  692. return name, false, false, nil
  693. }
  694. func isFieldStringable(tpe ast.Expr) bool {
  695. if ident, ok := tpe.(*ast.Ident); ok {
  696. switch ident.Name {
  697. case "int", "int8", "int16", "int32", "int64",
  698. "uint", "uint8", "uint16", "uint32", "uint64",
  699. "float64", "string", "bool":
  700. return true
  701. }
  702. } else if starExpr, ok := tpe.(*ast.StarExpr); ok {
  703. return isFieldStringable(starExpr.X)
  704. } else {
  705. return false
  706. }
  707. return false
  708. }
  709. type tagOptions []string
  710. func (t tagOptions) Contain(option string) bool {
  711. for i := 1; i < len(t); i++ {
  712. if t[i] == option {
  713. return true
  714. }
  715. }
  716. return false
  717. }
  718. func (t tagOptions) Name() string {
  719. return t[0]
  720. }
  721. var Debug = false
  722. func debugLog(format string, args ...interface{}) {
  723. if Debug {
  724. log.Printf(format, args...)
  725. }
  726. }