1.1.8 • Published 2 months ago

proto2tsapi v1.1.8

Weekly downloads
-
License
MIT
Repository
-
Last release
2 months ago

用于把 proto 文件转换成 Typescript 的 api 文件

  1. 先把需要转换的 proto 文件确定好
  2. 依次遍历 proto 文件,然后转换成 ts 文件

注意事项:目前仅支持单个 proto 文件内存在单个 service,如单个 proto 文件存在多个 service,输出的 service 名称将会是最后一个 service 的名称

基于proto2api修改的 npm 包,在 proto2api 基础上拆分类型文件和 api 文件,将格式修改为自己需要的内容。

新版本特性

2024-03-14 v1.1.8: 更新了 config 文件对 depPath 和 protoDir 的支持

{
  "files": {
    ...
  },
  "output": "./src/api",
  "ignore": "google|swagger",
  "protoDir": "./proto/", // 设置读取proto的根路径
  "depPath": "./proto/" // 设置读取proto时依赖包的路径
}

2023-10-13 v1.1.7:customVariate 新增了文件名入参

interface ICustomVariateParams {
  name: string;
  comment?: string;
  url: string;
  redirectUrl?: string;
  method: "get" | "post" | "put" | "patch" | "delete";
  res: string;
  req: string;
  pkgName: string;
  srvName: string;
  fileName: string; // new!
}

const METHOD_NAME = (params: ICustomVariateParams) => {
  const { pkgName, srvName, name, fileName } = params;
  return `${fileName}/${pkgName}.${srvName}/${name}`;
};
module.exports = { METHOD_NAME };

2023-10-09 v1.1.6:修复互相依赖情况下的报错导致的中断

2023-7-28 v1.1.5:导出的 apiName 会自动带/

2023-7-28 v1.1.4:新增 excel 导出 API 的功能,如有需要请配置 config.expApiPath 路径

{
  "files": {
    "./": [
      "example.proto"
    ]
  },
  ...
  "expApiPath":"./apiExport/apiExport.xlsx",
  ...
}

2023-3-10 v1.1.3:删除多余的 console.log

2023-3-10 v1.1.2:

  1. 更改了 enum 的转换方式,现在能正常转换成对应的数值,支持 proto 内断连的 enum 数值了。参考如下:
// 现在默认不会转换成旧版本的字符串值了,如有需要请在配置文件内设置 transEnum2String:true
export enum YesOrNo {
  // 否
  No = 0,
  // 是
  Yes = 1,
}

export enum Status {
  // 草稿
  Draft = 0,
  // 已完成
  Done = 3,
  // 未提交
  Todo = 4,
}
  1. 新增了自定义变量的功能,现在可以通过自定义变量插入模板代码中的任意部位。注意!!!模板代码使用自定义变量时需以$符号开始和结尾。 参考如下:
// proto2tsapi.json 在配置文件内新增了customVariate配置,接收自定义变量的文件路径
{
  "files": {
    "./": [
      "example.proto"
    ]
  },
  "output": "./src/api/example",
  "ignore": "google|swagger",
  "FORMAT_URL_METHOD": "./formatUrlMethod.ts", // 此变量依然保留,以兼容旧版本
  "customVariate": "./customVariate.ts", // 现在可以通过使用自定义变量来实现FORMAT_URL_METHOD的功能
  "transEnum2String":false, // 如需转换成key值字符串的enum请设置成true
  "defaultTemplate": [
    "$COMMENT",
    "export const $API_NAME = ($REQ_KEY: Types.$REQ_TYPE) => {",
    "return request<RspStructure<Types.$RSP_TYPE>>({",
    "url:'$FORMAT_URL_METHOD',",
    "method: '$API_METHOD',",
    "$REQ_KEY,",
    "} as AxiosConfig<Types.$REQ_TYPE, Types.$REQ_TYPE>);",
    "};"
    "// $METHOD_NAME1$" // 使用自定义变量请以$开头和结尾,根据下面的文件内容配置,这里的结果会转换成 // 13
  ],
  ...
}
// customVariate.ts 新增的[自定义变量格式化函数]文件内

interface ApiFunction {
  name: string;
  comment?: string;
  req: PropertyType;
  url: string;
  redirectUrl?: string;
  res: PropertyType;
  method: "get" | "post" | "put" | "patch" | "delete";
}

interface ICustomVariateParams extends Omit<ApiFunction, "req" | "res"> {
  res: string;
  req: string;
  pkgName: string;
  srvName: string;
}
interface ICustomVariate {
  [k: string]: (parms: ICustomVariateParams) => string;
}

const METHOD_NAME = (p: ICustomVariate) => {
  return p.req;
};
const METHOD_NAME1 = () => {
  return "13";
};
const request = () => {
  return "6666";
};

// 自定义变量名可以自己取,但是建议与模板内其他变量和代码段字符区分开来,推荐全大写的下划线写法

module.exports = { METHOD_NAME, METHOD_NAME1, request };

2022-11-29 v1.1.1:

  1. 修复了 customTemplate 和 templateConfig 匹配不上的问题,现在可以正常使用 customTemplate 了。

2022-9-02 v1.1.0:

  1. 新增了 printRoot 配置项,值为 Boolean,可在项目根目录输出解析 proto 文件生成的 root 对象的 json 文件,非必填;

  2. 新增了预处理规则,pretreatRules 配置项,可用于替换 proto 文件内的部分内容,解决一些不兼容的语法问题

  3. 新增了 proto3 中配置了 validate 规则的类型输出支持,现在可以在配置了 validate 规则的 proto 文件中区分是否必填项;※默认所有字段均为可选※,只有配置了 validate 选项的字段会输出必填项的类型;参考如下:

    config 文件:

 "pretreatRules": { // 用于替换proto文件内的部分匹配内容,如配置了此项,会使用此项规则修改后的proto文件进行转换;不会修改原proto文件; 非必填项
        "./proto/example/example.proto": [  // key名是配置的路径,可配置多个规则,均会应用到该文件上
            {
                "searchValue": "{ in: [ \\\"未处理\\\", \\\"已处理\\\" ] }",  // 被替代的内容,注意:此内容是匹配JSON.stringify后的文本信息,按照json的规则,对特殊的符号匹配需进行转义,例如 "" 和 \ 等等;
                "replaceValue": "0"  // 需要替换成的内容
            }
        ],
     	"./proto/hello.proto":[] // 可为多个文件配置多个规则
    }

proto 文件:

import "validate.proto";

message Example {
    uint64 id       	 = 1; // 这种默认会转换成可选项的类型
    string username      = 1 [(validate.rules).string.min_len = 2]; // 这种配置了validate.rules的会转换成必填项的类型
    string status        = 4 [(validate.rules).string = { in: [ "未处理", "已处理" ] }]; // 这种配合插件使用的情况无法解析,会报错,需配合新增的pretreatRules配置使用
}

转换后的 types 文件:

export interface Example {
  todo_id?: string;
  username: string;
  status: string; // 需配置pretreatRules解决语法问题,否则会报错,后面的内容都不会被转换
}

2022-8-31 v1.0.6:

  1. 修复了生产多个文件的 api 时,$API_URL变量中自动拼接的serviceName只为最后一个的bug,现在已废弃$API_URL 变量;
  2. 新增了$PKG_NAME和$SRV_NAME 两个变量,用于在 FORMAT_URL_METHOD 的格式化函数中使用
  3. 修复了配置 files 里的*全选项时,默认生成根目录下所有 proto 文件的 bug,现在能正常按 files 配置里的文件夹路径单个文件夹生效了
  4. 修复了部分非必填配置项如不存在仍然报错的 bug,修复的配置项如下:REQ_KEY、templateConfig、customTemplate

快速开始

npm install -g proto2tsapi

cd proto2api

proto2tsapi -c examples/config.json

命令行说明

Usage: proto2tsapi [options]

Convert proto file to api file

Options:
Options:
  -V, --version         output the version number
  --debug               load code with ts-node for debug
  -c, --config <path>   config.json path
  --depPath <type>      the address of the external dependency proto library.
                        eq: /common/proto3 (default: "")
  -h, --help            display help for command

配置文件

参考配置项如下

{
  "files": {
    // 此处配置需转换的proto文件的路径,key是路径,value是文件名的数组集合;**必填项**
    "./proto/examples": ["hello.proto"],
    "./proto": [
      "*" // 如果数组的首项是 * ,则会转换该文件夹下的所有proto文件
    ]
  },
  "output": "./dist", // 输出文件的路径; **必填项**
  "printRoot": false, // 可在项目根目录输出解析proto文件生成的root对象的json文件; 非必填
  "ignore": "google|swagger", // proto文件可被忽略的部分,例如"google|swagger" , 可参考proto2api; 非必填
  "FORMAT_URL_METHOD": "./formatUrlMethod.ts", // 配置格式化函数的文件路径,需返回字符串;非必填
  "REQ_KEY": {
    // 配置不同请求方式下,请求参数的key名,将会作为变量用在生成api代码的片段上;默认值为data; 非必填
    "get": "params",
    "post": "data",
    "put": "put",
    "delete": "del"
  },
  "templateConfig": {
    // 配置接口与代码片段模板的对应关系,非必填;通过这个可以配置不同接口使用不同模板生成
    "pageLoading": [
      "hello/GetGame" // 匹配规则是 `${文件名}/${service里的rpc方法名}`
    ],
    "unPageLoading": ["hello/BatchGetGame"]
  },
  "defaultTemplate": [
    // 默认代码片段的模板; **必填项**
    "$COMMENT",
    "export const $API_NAME = ($REQ_KEY: $REQ_TYPE) => {",
    "return request<ResponseStructure<$RSP_TYPE>>({",
    "url:'$FORMAT_URL_METHOD',",
    "method: '$API_METHOD',",
    "$REQ_KEY,",
    "} as AxiosConfig<$REQ_TYPE, $REQ_TYPE>);",
    "};"
  ],
  "customTemplate": {
    // 自定义不同代码片段的模板,非必填; 需搭配templateConfig项使用
    "pageLoading": [
      "$COMMENT",
      "export const $API_NAME = ($REQ_KEY: $REQ_TYPE) => {",
      "return request<ResponseStructure<$RSP_TYPE>>({",
      "url:'$PKG_NAME.$SRV_NAME/$API_NAME',",
      "method: '$API_METHOD',",
      "$REQ_KEY,",
      "pageLoading:'pageLoading'",
      "} as AxiosConfig<$REQ_TYPE, $REQ_TYPE>);",
      "};"
    ],
    "unPageLoading": [
      "$COMMENT",
      "export const $API_NAME = ($REQ_KEY: $REQ_TYPE) => {",
      "return request<ResponseStructure<$RSP_TYPE>>({",
      "url:'$PKG_NAME.$SRV_NAME/$API_NAME',",
      "method: '$API_METHOD',",
      "$REQ_KEY,",
      "pageLoading:'none'",
      "} as AxiosConfig<$REQ_TYPE, $REQ_TYPE>);",
      "};"
    ]
  },
  "importTemplate": [
    // 导入依赖相关的代码片段模板,可根据自己需求定义,非必填
    "import * as Types from './types';",
    "const { request } = useAxios();"
  ],
  "pretreatRules": {
    // 用于替换proto文件内的部分匹配内容,如配置了此项,会使用此项规则修改后的proto文件进行转换;不会修改原proto文件; 非必填项
    "./proto/example/example.proto": [
      // key名是配置的路径,可配置多个规则,均会应用到该文件上
      {
        "searchValue": "{ in: [ \\\"未处理\\\", \\\"已处理\\\" ] }", // 被替代的内容,注意:此内容是匹配JSON.stringify后的文本信息,按照json的规则,对特殊的符号匹配需进行转义,例如 "" 和 \ 等等;
        "replaceValue": "0" // 需要替换成的内容
      }
    ],
    "./proto/hello.proto": [] // 可为多个文件配置多个规则
  },
  "printRoot": false // 可在项目根目录输出解析proto文件生成的root对象的json文件,调试用,非必填;
}

代码片段变量说明

"$COMMENT": proto文件的注释,
"$API_NAME": proto文件的api名称,
"$REQ_KEY": 不同请求方式下,请求参数的key名; 默认值是:'data',
"$REQ_TYPE": proto文件的请求参数类型,
"$RSP_TYPE": proto文件的相应数据类型,
"$PKG_NAME": proto文件的package名称,
"$SRV_NAME": proto文件接口的service名称,
"$API_METHOD": proto文件接口的方法名称,
"$FORMAT_URL_METHOD": 格式化函数的返回结果

格式化函数示例

const formatUrlMethod = (PKG_NAME, SRV_NAME, API_NAME) => {
  // 参数1可以取到$PKG_NAME的值,参数2可以取到$SRV_NAME的值,参数3可以取到$API_NAME的值
  return `prefix ${PKG_NAME}.${SRV_NAME} conjunctions ${API_NAME} suffix`; // 可以根据入参自由拼接,返回的结果会体现到模板的$FORMAT_URL_METHOD变量上
};

exports.FORMAT_URL_METHOD = formatUrlMethod; // 此处导出的时候必须使用FORMAT_URL_METHOD命名

转换示例

proto 文件

syntax = "proto3";
package hello;

import "google/protobuf/empty.proto";
import "google/api/annotations.proto";

enum Status {
    UNKNOWN = 0;
    // 新创建
    NEW = 1;
  }

message InfoReq {
    int32 id = 1 [proto3_optional = true]; // id
    string user_name = 2 ; //  optional
}
message InfoResp {
    int32 ret_code = 1 [json_name = "retCode"];
    string ret_msg = 2  [json_name = "retMsg"];
    Status status = 3;
}

service API {
   rpc GetDemo(google.protobuf.Empty) returns (google.protobuf.Empty) {
       option (google.api.http) = {
           get: "/get"
           body: "*"
         };
   }
   rpc PostDemo(InfoReq) returns (InfoResp) {
       option (google.api.http) = {
           post: "/post"
       };
   }

}


message GetRequest {
    int64 id = 1;
    int64 external_id = 2;
    int32 external_type = 3;
  }

service API2 {
    // @method get
    // @redirect api/get-game
    rpc GetGame(GetRequest) returns (InfoResp);
    rpc BatchGetGame(GetRequest) returns (InfoResp);
}

转换后的 api 文件

/* eslint-disable */
/** @format */

// This is code generated automatically by the proto2api, please do not modify

import * as Types from "./types";
const { request } = useAxios();

// null
// API

export const GetDemo = (params: {}) => {
  return request<ResponseStructure<{}>>({
    url: "prefix /hello.API2 conjunctions GetDemo suffix",
    method: "get",
    params,
  } as AxiosConfig<{}, {}>);
};

export const PostDemo = (data: InfoReq) => {
  return request<ResponseStructure<InfoResp>>({
    url: "prefix /hello.API2 conjunctions PostDemo suffix",
    method: "post",
    data,
  } as AxiosConfig<InfoReq, InfoResp>);
};

// null
// API2

// @method get
// @originUrl:

export const GetGame = (params: GetRequest) => {
  return request<ResponseStructure<InfoResp>>({
    url: "prefix /hello.API2 conjunctions GetGame suffix",
    method: "get",
    params,
  } as AxiosConfig<GetRequest, InfoResp>);
};

export const BatchGetGame = (data: GetRequest) => {
  return request<ResponseStructure<InfoResp>>({
    url: "/hello.API2/BatchGetGame",
    method: "post",
    data,
    pageLoading: "none",
  } as AxiosConfig<GetRequest, InfoResp>);
};

转换后的 types 文件

/* eslint-disable */
/** @format */

// This is code generated automatically by the proto2api, please do not modify

export enum Status {
  UNKNOWN = "UNKNOWN",
  // 新创建
  NEW = "NEW",
}
export interface InfoReq {
  // id @int32
  id?: number;
  // optional
  user_name?: string;
}

export interface InfoResp {
  //  @int32
  retCode: number;
  retMsg: string;
  status: Status;
}

export interface GetRequest {
  //  @int64
  id: string;
  //  @int64
  external_id: string;
  //  @int32
  external_type: number;
}

参考文档

Google Protobuf 语法指南 https://developers.google.com/protocol-buffers/docs/proto3

proto2api 参考链接https://www.npmjs.com/package/proto2api

1.1.8

2 months ago

1.1.7

7 months ago

1.1.6

7 months ago

1.1.5

10 months ago

1.1.4

10 months ago

1.1.1

1 year ago

1.1.3

1 year ago

1.1.2

1 year ago

1.0.2

2 years ago

1.1.0

2 years ago

1.0.6

2 years ago

1.0.5

2 years ago

1.0.4

2 years ago

1.0.3

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago