utils 系列包

utils 系列包包含:

  1. api 包,用于读取项目源码,并生成与 API 有关的所有数据结构,产出的结构可用于生成文档和客户端。
  2. builder 包,利用 api 包读取源码并生成 API 数据。
  3. generators/golang 包,利用 api 包提供的数据结构生成 golang 客户端。
  4. generators/swagger 包,利用 api 包提供的数据结构生成 API 文档。
  5. generators/utils 包,提供公共工具给其他生成器使用。
  6. printer 包,提供了一个在 Terminal 中打印表格的功能。
  7. project 包,提供了基础工具用于读取项目配置文件,通常是 nirvana.yaml。

除了 printer 包以外,其他包都是用于生成文档和客户端用的。

在 api 包中,提供了如下功能:

  1. 对应 golang type 的 Type
    为了能让 golang type 能转换为可读的数据结构,构建了 Type 相关类型:

    1. // TypeName is unique name for go types.
    2. type TypeName string
    3. // TypeNameInvalid indicates an invalid type name.
    4. const TypeNameInvalid = ""
    5. // StructField describes a field of a struct.
    6. type StructField struct {
    7. // Name is the field name.
    8. Name string
    9. // Comments of the type.
    10. Comments string
    11. // PkgPath is the package path that qualifies a lower case (unexported)
    12. // field name. It is empty for upper case (exported) field names.
    13. PkgPath string
    14. // Type is field type name.
    15. Type TypeName
    16. // Tag is field tag.
    17. Tag reflect.StructTag
    18. // Offset within struct, in bytes.
    19. Offset uintptr
    20. // Index sequence for Type.FieldByIndex.
    21. Index []int
    22. // Anonymous shows whether the field is an embedded field.
    23. Anonymous bool
    24. }
    25. // FuncField describes a field of function.
    26. type FuncField struct {
    27. // Name is the field name.
    28. Name string
    29. // Type is field type name.
    30. Type TypeName
    31. }
    32. // Type describes an go type.
    33. type Type struct {
    34. // Name is short type name.
    35. Name string
    36. // Comments of the type.
    37. Comments string
    38. // PkgPath is the package for this type.
    39. PkgPath string
    40. // Kind is type kind.
    41. Kind reflect.Kind
    42. // Key is map key type. Only used in map.
    43. Key TypeName
    44. // Elem is the element type of map, slice, array, pointer.
    45. Elem TypeName
    46. // Fields contains all struct fields of a struct.
    47. Fields []StructField
    48. // In presents fields of function input parameters.
    49. In []FuncField
    50. // Out presents fields of function output results.
    51. Out []FuncField
    52. // Conflict identifies the index of current type in a list of
    53. // types which have same type names. In most cases, this field is 0.
    54. Conflict int
    55. }
  2. 对应 Nirvana API 的 Definition
    此处的 Definition 大部分字段与 definition 包中的相同,之所以不复用之前的结构,是因为有部分类型相关的字段稍有不同。

    1. // Parameter describes a function parameter.
    2. type Parameter struct {
    3. // Source is the parameter value generated from.
    4. Source definition.Source
    5. // Name is the name to get value from a request.
    6. Name string
    7. // Description describes the parameter.
    8. Description string
    9. // Type is parameter object type.
    10. Type TypeName
    11. // Default is encoded default value.
    12. Default []byte
    13. }
    14. // Result describes a function result.
    15. type Result struct {
    16. // Destination is the target for the result.
    17. Destination definition.Destination
    18. // Description describes the result.
    19. Description string
    20. // Type is result object type.
    21. Type TypeName
    22. }
    23. // Example is just an example.
    24. type Example struct {
    25. // Description describes the example.
    26. Description string
    27. // Type is result object type.
    28. Type TypeName
    29. // Instance is encoded instance data.
    30. Instance []byte
    31. }
    32. // Definition is complete version of def.Definition.
    33. type Definition struct {
    34. // Method is definition method.
    35. Method definition.Method
    36. // HTTPMethod is http method.
    37. HTTPMethod string
    38. // HTTPCode is http success code.
    39. HTTPCode int
    40. // Summary is a brief of this definition.
    41. Summary string
    42. // Description describes the API handler.
    43. Description string
    44. // Consumes indicates how many content types the handler can consume.
    45. // It will override parent descriptor's consumes.
    46. Consumes []string
    47. // Produces indicates how many content types the handler can produce.
    48. // It will override parent descriptor's produces.
    49. Produces []string
    50. // ErrorProduces is used to generate data for error. If this field is empty,
    51. // it means that this field equals to Produces.
    52. // In some cases, succeessful data and error data should be generated in
    53. // different ways.
    54. ErrorProduces []string
    55. // Function is a function handler. It must be func type.
    56. Function TypeName
    57. // Parameters describes function parameters.
    58. Parameters []Parameter
    59. // Results describes function retrun values.
    60. Results []Result
    61. // Examples contains many examples for the API handler.
    62. Examples []Example
    63. }
  3. 用于表示代码注释的 Comments
    在源码解析的时候,通常需要通过注释实现一些特殊功能,因此要对注释进行分析。目前注释特殊格式是 +nirvana:api=option:"value"

    1. const (
    2. // CommentsOptionDescriptors is the option name of descriptors.
    3. CommentsOptionDescriptors = "descriptors"
    4. // CommentsOptionModifiers is the option name of modifiers.
    5. CommentsOptionModifiers = "modifiers"
    6. // CommentsOptionAlias is the option name of alias.
    7. CommentsOptionAlias = "alias"
    8. // CommentsOptionOrigin is the option name of original name.
    9. CommentsOptionOrigin = "origin"
    10. )
    11. // Comments is parsed from go comments.
    12. type Comments struct {
    13. lines []string
    14. options map[string][]string
    15. }
    16. var optionsRegexp = regexp.MustCompile(`^[ \t]*\+nirvana:api[ \t]*=(.*)$`)
    17. var options = []string{CommentsOptionDescriptors, CommentsOptionModifiers, CommentsOptionAlias}
    18. // ParseComments parses comments and extracts nirvana options.
    19. func ParseComments(comments string) *Comments
  4. 用于分析源码的 Analyzer
    Analyzer 可以读取源码,获取结构对象和注释信息。

    1. // Analyzer analyzes go packages.
    2. type Analyzer struct {
    3. ...
    4. }
    5. // NewAnalyzer creates a code ananlyzer.
    6. func NewAnalyzer(root string) *Analyzer
    7. // Import imports a package and all packages it depends on.
    8. func (a *Analyzer) Import(path string) (*types.Package, error)
    9. // PackageComments returns comments above package keyword.
    10. // Import package before calling this method.
    11. func (a *Analyzer) PackageComments(path string) []*ast.CommentGroup
    12. // Packages returns packages under specified directory (including itself).
    13. // Import package before calling this method.
    14. func (a *Analyzer) Packages(parent string, vendor bool) []string
    15. // FindPackages returns packages which contain target.
    16. // Import package before calling this method.
    17. func (a *Analyzer) FindPackages(target string) []string
    18. // Comments returns immediate comments above pos.
    19. // Import package before calling this method.
    20. func (a *Analyzer) Comments(pos token.Pos) *ast.CommentGroup
    21. // ObjectOf returns declaration object of target.
    22. func (a *Analyzer) ObjectOf(pkg, name string) (types.Object, error)
  5. 集合上述所有功能的 Container
    Container 读取源码并进行分析,产出 API 相关的所有定义和类型信息。API 定义和类型信息可以用来生成 API 文档和客户端。

    1. // Definitions describes all APIs and its related object types.
    2. type Definitions struct {
    3. // Definitions holds mappings between path and API descriptions.
    4. Definitions map[string][]Definition
    5. // Types contains all types used by definitions.
    6. Types map[TypeName]*Type
    7. }
    8. // Container contains informations to generate APIs.
    9. type Container struct {
    10. ...
    11. }
    12. // NewContainer creates API container.
    13. func NewContainer(root string) *Container
    14. // AddModifier add definition modifiers to container.
    15. func (ac *Container) AddModifier(modifiers ...service.DefinitionModifier)
    16. // AddDescriptor add descriptors to container.
    17. func (ac *Container) AddDescriptor(descriptors ...definition.Descriptor)
    18. // Generate generates API definitions.
    19. func (ac *Container) Generate() (*Definitions, error)

builder 包相对 api 包来说就简单很多了,这个包里包含一个 API Builder:

  1. // APIBuilder builds api definitions by specified package.
  2. type APIBuilder struct {
  3. ...
  4. }
  5. // NewAPIBuilder creates an api builder.
  6. func NewAPIBuilder(root string, paths ...string) *APIBuilder
  7. // Build build api definitions.
  8. func (b *APIBuilder) Build() (*api.Definitions, error)

API Builder 首先会利用 Analyzer 去读取指定路径的源码,然后从中找到标记了 modifiers 和 descriptors 选项的注释。两个选项的值对应两个函数,分别返回 Modifier 和 Descriptor。然后动态生成一个 main.go 文件 import 这两个函数对应包,然后调用这两个函数,取得返回值。得到返回值之后则利用 api 包的 Container 来生成 API 定义和类型信息。API Builder 执行 main.go 后通过 stdout 取得返回值,反序列化成 Definitions 结构,然后再返回给 API Builder 的调用者。这样就完成了对一个项目的 API 信息的提取。

golang 包和 swagger 包实际上都是利用了 API Builder 的返回结果,构建出相应的客户端和文档。golang 包会为每一个 API 生成一个客户端函数,这个函数的结构和服务读基本一致。函数体的实现则是直接使用了 rest 包 Client 接口。swagger 包则是利用了 github.com/go-openapi/spec 将 API 定义和类型转换成了 openapi 的定义。