mirror of
https://github.com/go-home-admin/toolset.git
synced 2025-12-24 13:37:52 +08:00
1、post的payload统一改为application/json 2、支持多语言,新增执行参数-lang=语言标识,以“//@lang=语言 说明”声明指定语言说明 3、优化Description显示,tag换行显示,引用对象时采用本地说明 4、支持example定义,用“//@example=”或“//@example()”声明,前者不支持空格 5、增加path的参数及说明,于请求声明上一行添加注释,例如:`option (http.Get) = "/user/:id";`,上一行添加:`// @query=id @lang=语言标识 @format=string @example=ABC 说明文本`,其中query是必须指定声明,format默认为int 二、生成pgorm时,取消[]byte生成关于list的func
374 lines
9.9 KiB
Go
374 lines
9.9 KiB
Go
package commands
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"github.com/ctfang/command"
|
|
"github.com/go-home-admin/toolset/console/commands/openapi"
|
|
"github.com/go-home-admin/toolset/parser"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"regexp"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// Js @Bean
|
|
type Js struct{}
|
|
|
|
var isResponse bool
|
|
|
|
func (j *Js) Configure() command.Configure {
|
|
return command.Configure{
|
|
Name: "make:js",
|
|
Description: "根据swagger生成js请求文件",
|
|
Input: command.Argument{
|
|
Option: []command.ArgParam{
|
|
{
|
|
Name: "in",
|
|
Description: "swagger.json路径, 可本地可远程",
|
|
Default: "@root/web/swagger.json",
|
|
},
|
|
{
|
|
Name: "out",
|
|
Description: "js文件输出路径",
|
|
Default: "@root/resources/src/api/swagger_gen.js",
|
|
},
|
|
{
|
|
Name: "tag",
|
|
Description: "只生成指定tag的请求",
|
|
},
|
|
{
|
|
Name: "http_from",
|
|
Description: "指定import的http函数位置",
|
|
Default: "@/utils/request",
|
|
},
|
|
{
|
|
Name: "info_tags",
|
|
Description: "指定注释中的tag显示于接口说明",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func (j *Js) Execute(input command.Input) {
|
|
root := getRootPath()
|
|
in := input.GetOption("in")
|
|
in = strings.Replace(in, "@root", root, 1)
|
|
inSwaggerStr := ""
|
|
if strings.Index(in, "http") == 0 {
|
|
// 远程获取文件
|
|
req, _ := http.NewRequest("GET", in, nil)
|
|
res, _ := http.DefaultClient.Do(req)
|
|
defer res.Body.Close()
|
|
//得到返回结果
|
|
body, _ := io.ReadAll(res.Body)
|
|
inSwaggerStr = string(body)
|
|
} else {
|
|
body, _ := os.ReadFile(in)
|
|
inSwaggerStr = string(body)
|
|
}
|
|
out := input.GetOption("out")
|
|
out = strings.Replace(out, "@root", root, 1)
|
|
|
|
swagger := openapi.Spec{
|
|
Swagger: "2.0",
|
|
Info: openapi.Info{
|
|
Title: "2",
|
|
Description: "2",
|
|
Version: "2",
|
|
},
|
|
Host: "api.swagger.com",
|
|
Schemes: []string{"https"},
|
|
BasePath: "/",
|
|
Produces: []string{"application/json"},
|
|
Paths: make(map[string]*openapi.Path),
|
|
Definitions: map[string]*openapi.Schema{
|
|
"google.protobuf.Any": {
|
|
Type: "object",
|
|
},
|
|
},
|
|
Parameters: nil,
|
|
Extensions: nil,
|
|
GlobalOptions: nil,
|
|
}
|
|
_ = json.Unmarshal([]byte(inSwaggerStr), &swagger)
|
|
fixSwaggerType(&swagger)
|
|
|
|
tag := input.GetOption("tag")
|
|
infoTags := input.GetOptions("info_tags")
|
|
str := fmt.Sprintf("import http from '%s'\n", input.GetOption("http_from"))
|
|
for _, url := range sortPathMap(swagger.Paths) {
|
|
paths := swagger.Paths[url]
|
|
re, _ := regexp.Compile("\\$\\[.+\\]")
|
|
url = re.ReplaceAllString(url, "")
|
|
url, funcName, params := analysisUrl(url)
|
|
urlParams := make([]*openapi.Parameter, 0)
|
|
for _, p := range params {
|
|
urlParams = append(urlParams, &openapi.Parameter{
|
|
Name: p,
|
|
Required: true,
|
|
Type: "string",
|
|
})
|
|
}
|
|
methods := make([]makeJsCache, 0)
|
|
methods = append(methods, makeJsCache{e: paths.Get, cm: canMakeJs(paths.Get, tag), method: "get"})
|
|
methods = append(methods, makeJsCache{e: paths.Put, cm: canMakeJs(paths.Put, tag), method: "put"})
|
|
methods = append(methods, makeJsCache{e: paths.Post, cm: canMakeJs(paths.Post, tag), method: "post"})
|
|
methods = append(methods, makeJsCache{e: paths.Patch, cm: canMakeJs(paths.Patch, tag), method: "patch"})
|
|
methods = append(methods, makeJsCache{e: paths.Delete, cm: canMakeJs(paths.Delete, tag), method: "delete"})
|
|
for _, method := range methods {
|
|
if method.cm {
|
|
isResponse = false
|
|
//Tags说明
|
|
var tagInfo string
|
|
for _, s := range infoTags {
|
|
info := getTagInfo(method.e.Description, s)
|
|
if info != "" {
|
|
tagInfo += fmt.Sprintf("\n * @%s %s", s, info)
|
|
}
|
|
}
|
|
var paramNames []string
|
|
var paramStr string
|
|
if method.method == "get" {
|
|
paramStr = genJsRequest(method.e.Parameters, swagger)
|
|
} else if method.e.RequestBody != nil {
|
|
paramStr = "\n * @param {" + getObjectStrFromRef(method.e.RequestBody.Content.Json.Schema.Ref, swagger) + "} data"
|
|
}
|
|
var dataStr string
|
|
if paramStr != "" {
|
|
paramNames = append(paramNames, "data")
|
|
dataStr = ", data"
|
|
}
|
|
if len(urlParams) > 0 {
|
|
for _, urlParam := range urlParams {
|
|
paramStr += "\n * @param {string|number} " + urlParam.Name
|
|
paramNames = append(paramNames, urlParam.Name)
|
|
}
|
|
}
|
|
var response string
|
|
if _, ok := method.e.Responses["200"]; ok {
|
|
if method.e.Responses["200"].Schema != nil {
|
|
isResponse = true
|
|
response = getObjectStrFromRef(method.e.Responses["200"].Schema.Ref, swagger)
|
|
}
|
|
}
|
|
str += fmt.Sprintf(`
|
|
/**
|
|
* %v%v%v
|
|
* @returns {Promise<{code:number,data:%v,message:string}>}
|
|
* @callback
|
|
*/
|
|
export async function %v%v(%v) {
|
|
return await http.%v(%v%v)
|
|
}
|
|
`,
|
|
method.e.Summary,
|
|
tagInfo,
|
|
paramStr,
|
|
response,
|
|
parser.StringToHump(strings.Trim(strings.ReplaceAll(funcName, "/", "_"), "_")),
|
|
parser.StringToHump(method.method),
|
|
strings.Join(paramNames, ", "),
|
|
method.method,
|
|
url,
|
|
dataStr,
|
|
)
|
|
}
|
|
}
|
|
}
|
|
_ = os.WriteFile(out, []byte(str), 0766)
|
|
}
|
|
|
|
func sortPathMap(m map[string]*openapi.Path) []string {
|
|
var keys []string
|
|
for k := range m {
|
|
keys = append(keys, k)
|
|
}
|
|
//按字典升序排列
|
|
sort.Strings(keys)
|
|
return keys
|
|
}
|
|
|
|
func genJsRequest(p openapi.Parameters, swagger openapi.Spec) string {
|
|
if len(p) == 0 {
|
|
return ""
|
|
}
|
|
str := "\n * @param {{"
|
|
for i, parameter := range p {
|
|
t := parameter.Type
|
|
switch parameter.Type {
|
|
case "integer", "Number":
|
|
t = "number"
|
|
case "array":
|
|
t = "[]"
|
|
if parameter.Format != "" {
|
|
if ty, ok := protoToSwagger[parameter.Format]; ok {
|
|
parameter.Format = ty
|
|
}
|
|
t = parameter.Format + t
|
|
} else if parameter.Items != nil {
|
|
t = getObjectStrFromRef(parameter.Items.Ref, swagger) + t
|
|
}
|
|
case "", "object":
|
|
if parameter.Schema != nil {
|
|
t = getObjectStrFromRef(parameter.Schema.Ref, swagger)
|
|
}
|
|
}
|
|
if i != 0 {
|
|
str += ","
|
|
}
|
|
if !parameter.Required {
|
|
parameter.Name = parameter.Name + "?"
|
|
}
|
|
str += fmt.Sprintf(`%v:%v`, parameter.Name, t)
|
|
}
|
|
return str + "}} data"
|
|
}
|
|
|
|
type makeJsCache struct {
|
|
e *openapi.Endpoint
|
|
cm bool
|
|
method string
|
|
}
|
|
|
|
func canMakeJs(e *openapi.Endpoint, tag string) bool {
|
|
makeJs := false
|
|
if e != nil {
|
|
if tag == "" {
|
|
makeJs = true
|
|
} else {
|
|
for _, t := range e.Tags {
|
|
if t == tag {
|
|
makeJs = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return makeJs
|
|
}
|
|
|
|
func analysisUrl(url string) (newUrl string, funcName string, params []string) {
|
|
re, _ := regexp.Compile("/:([^/\\n\\r])+")
|
|
funcName = url
|
|
newUrl = fmt.Sprintf("`%v`", url)
|
|
for _, s := range re.FindAllString(funcName, -1) {
|
|
p := strings.Replace(s, "/:", "", 1)
|
|
params = append(params, p)
|
|
funcName = strings.Replace(funcName, s, "_"+p, 1)
|
|
newUrl = strings.Replace(newUrl, s, "/${"+p+"}", 1)
|
|
}
|
|
return
|
|
}
|
|
|
|
func fixSwaggerType(swagger *openapi.Spec) {
|
|
for url, path := range swagger.Paths {
|
|
if path.Get != nil {
|
|
for i, parameter := range path.Get.Parameters {
|
|
if parameter.Schema != nil {
|
|
key := strings.Replace(parameter.Schema.Ref, "#/definitions/", "", 1)
|
|
if _, ok := swagger.Definitions[key]; ok {
|
|
swagger.Paths[url].Get.Parameters[i].Type = swagger.Definitions[key].Format
|
|
}
|
|
}
|
|
swagger.Paths[url].Get.Parameters[i].Type = strings.ToLower(swagger.Paths[url].Get.Parameters[i].Type)
|
|
}
|
|
}
|
|
if path.Post != nil {
|
|
for i, parameter := range path.Post.Parameters {
|
|
if parameter.Schema != nil {
|
|
key := strings.Replace(parameter.Schema.Ref, "#/definitions/", "", 1)
|
|
if _, ok := swagger.Definitions[key]; ok {
|
|
swagger.Paths[url].Post.Parameters[i].Type = swagger.Definitions[key].Format
|
|
}
|
|
}
|
|
swagger.Paths[url].Post.Parameters[i].Type = strings.ToLower(swagger.Paths[url].Post.Parameters[i].Type)
|
|
}
|
|
}
|
|
if path.Put != nil {
|
|
for i, parameter := range path.Put.Parameters {
|
|
if parameter.Schema != nil {
|
|
key := strings.Replace(parameter.Schema.Ref, "#/definitions/", "", 1)
|
|
if _, ok := swagger.Definitions[key]; ok {
|
|
swagger.Paths[url].Put.Parameters[i].Type = swagger.Definitions[key].Format
|
|
}
|
|
}
|
|
swagger.Paths[url].Put.Parameters[i].Type = strings.ToLower(swagger.Paths[url].Put.Parameters[i].Type)
|
|
}
|
|
}
|
|
if path.Patch != nil {
|
|
for i, parameter := range path.Patch.Parameters {
|
|
if parameter.Schema != nil {
|
|
key := strings.Replace(parameter.Schema.Ref, "#/definitions/", "", 1)
|
|
if _, ok := swagger.Definitions[key]; ok {
|
|
swagger.Paths[url].Patch.Parameters[i].Type = swagger.Definitions[key].Format
|
|
}
|
|
}
|
|
swagger.Paths[url].Patch.Parameters[i].Type = strings.ToLower(swagger.Paths[url].Patch.Parameters[i].Type)
|
|
}
|
|
}
|
|
if path.Delete != nil {
|
|
for i, parameter := range path.Delete.Parameters {
|
|
if parameter.Schema != nil {
|
|
key := strings.Replace(parameter.Schema.Ref, "#/definitions/", "", 1)
|
|
if _, ok := swagger.Definitions[key]; ok {
|
|
swagger.Paths[url].Delete.Parameters[i].Type = swagger.Definitions[key].Format
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func getObjectStrFromRef(ref string, swagger openapi.Spec) string {
|
|
str := "{"
|
|
def := strings.Replace(ref, "#/definitions/", "", 1)
|
|
var params []string
|
|
if _, ok := swagger.Definitions[def]; ok {
|
|
if isEnum(swagger.Definitions[def]) {
|
|
return "number"
|
|
}
|
|
for key, schema := range swagger.Definitions[def].Properties {
|
|
if !isResponse && !parser.InArrString(key, swagger.Definitions[def].Required) {
|
|
key = key + "?"
|
|
}
|
|
params = append(params, fmt.Sprintf(`%v:%v`, key, getJsType(schema, swagger, ref)))
|
|
}
|
|
}
|
|
str += strings.Join(params, ",")
|
|
str += "}"
|
|
return str
|
|
}
|
|
|
|
func getJsType(schema *openapi.Schema, swagger openapi.Spec, ref string) string {
|
|
t := schema.Type
|
|
_ref := schema.Ref
|
|
if len(schema.AllOf) > 0 {
|
|
for _, s := range schema.AllOf {
|
|
if s.Ref != "" {
|
|
_ref = s.Ref
|
|
}
|
|
}
|
|
}
|
|
switch schema.Type {
|
|
case "integer", "Number":
|
|
t = "number"
|
|
case "array":
|
|
if schema.Items != nil {
|
|
t = getJsType(schema.Items, swagger, ref)
|
|
}
|
|
t += "[]"
|
|
case "object", "":
|
|
if ref == _ref {
|
|
t = "{}"
|
|
} else if _ref != "" {
|
|
t = getObjectStrFromRef(_ref, swagger)
|
|
}
|
|
}
|
|
return t
|
|
}
|