├── __tests__ ├── _utils.ts ├── genTsApi │ ├── renderImport.test.ts │ ├── renderEnum.test.ts │ └── renderComment.test.ts ├── swagger │ └── core.test.ts └── utils.test.ts ├── babel.config.js ├── Makefile ├── examples ├── enum │ └── enum.proto ├── hello.proto └── complex │ └── svc.proto ├── tsconfig.spec.json ├── .gitignore ├── tsconfig.json ├── src ├── index.ts ├── utils.ts ├── apiInterface.ts ├── proto │ ├── index.ts │ └── core.ts └── genTsApi.ts ├── package.json ├── common └── google │ ├── api │ ├── annotations.proto │ └── http.proto │ ├── protobuf │ ├── source_context.proto │ ├── empty.proto │ ├── struct.proto │ ├── wrappers.proto │ ├── duration.proto │ ├── any.proto │ ├── timestamp.proto │ ├── type.proto │ ├── api.proto │ ├── field_mask.proto │ └── descriptor.proto │ └── rpc │ ├── status.proto │ ├── code.proto │ └── error_details.proto ├── readme.md ├── bin └── index └── jest.config.ts /__tests__/_utils.ts: -------------------------------------------------------------------------------- 1 | export function trim(str) { 2 | return str.trim().replace(/\n\s+/g, "\n"); 3 | } 4 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ["@babel/preset-env", { targets: { node: "current" } }], 4 | "@babel/preset-typescript", 5 | ], 6 | }; 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | export PATH := $(shell pwd)/node_modules/.bin:$(PATH) 2 | 3 | .PHONY: publish 4 | 5 | clean: 6 | rm -rf dist 7 | 8 | publish: clean 9 | pnpm install 10 | pnpm run build 11 | npm version patch 12 | npm publish 13 | git push -------------------------------------------------------------------------------- /examples/enum/enum.proto: -------------------------------------------------------------------------------- 1 | 2 | syntax = "proto3"; 3 | package enum; 4 | 5 | enum Status { 6 | UNKNOWN = 0; 7 | NEW = 1; 8 | } 9 | 10 | message InfoResp { 11 | int32 ret_code = 1 [json_name = "retCode"]; 12 | string ret_msg = 2 [json_name = "retMsg"]; 13 | Status status = 3; 14 | } -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"], 7 | "noUnusedLocals": false, 8 | }, 9 | "include": [ 10 | "**/*.spec.ts", 11 | "**/*.spec.js", 12 | "**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /outsourcing 8 | 9 | # dependencies 10 | /node_modules 11 | 12 | 13 | # IDEs and editors 14 | /.idea 15 | .project 16 | .classpath 17 | .c9/ 18 | *.launch 19 | .settings/ 20 | .history 21 | 22 | # IDE - VSCode 23 | .vscode/* 24 | # System Files 25 | .DS_Store 26 | Thumbs.db 27 | 28 | node_modules 29 | 30 | 31 | .mock 32 | 33 | yarn-error.log 34 | coverage 35 | yarn.lock 36 | temp -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "sourceMap": true, 5 | "declaration": true, 6 | "strict": true, 7 | "skipLibCheck": true, 8 | "importHelpers": false, 9 | "moduleResolution": "node", 10 | "experimentalDecorators": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "removeComments": false, 14 | "noUnusedLocals": true, // debug 15 | "noImplicitAny": false, 16 | "noImplicitThis": false, 17 | "strictNullChecks": false, 18 | "outDir": "./dist", 19 | "baseUrl": "./src", 20 | "paths": { 21 | }, 22 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"] 23 | }, 24 | "include": [ 25 | "src/*.d.ts", 26 | "src/**/*.ts" 27 | ], 28 | "exclude": ["node_modules/**"] 29 | } -------------------------------------------------------------------------------- /__tests__/genTsApi/renderImport.test.ts: -------------------------------------------------------------------------------- 1 | import { renderComment } from "../../src/genTsApi"; 2 | 3 | describe("renderComment test", () => { 4 | test("Null character test", () => { 5 | expect(renderComment("")).toBe(""); 6 | }); 7 | test("Double slash comment", () => { 8 | const comment = `double slash comment`; 9 | const result = renderComment(comment); 10 | const expected = "// " + comment + "\n"; 11 | expect(result).toBe(expected); 12 | }); 13 | 14 | test("Multi-line comment", () => { 15 | const comment = `multi-line comment \nmulti-line comment`; 16 | const result = renderComment(comment); 17 | const expected = "// multi-line comment \n// multi-line comment\n"; 18 | expect(result).toBe(expected); 19 | }); 20 | 21 | test("Do not add new line-break comments", () => { 22 | const comment = `double slash comment`; 23 | const result = renderComment(comment, false); 24 | const expected = "// " + comment; 25 | expect(result).toBe(expected); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { outputFileSync } from "fs-extra"; 2 | import { getProto2ApiData } from "./proto"; 3 | import { success } from "./utils"; 4 | import { genCode } from "./genTsApi"; 5 | export * from "./proto"; 6 | export * from "./apiInterface"; 7 | export * from "./proto/core"; 8 | export * from "./genTsApi"; 9 | export * from "./utils"; 10 | 11 | export interface Options { 12 | files: string[]; // proto file 13 | output: string; 14 | protoDir: string; // proto dir 15 | apiName: string; 16 | apiPath: string; 17 | apiPrefixPath: string; 18 | depPath: string; 19 | ignore?: RegExp; // ignore 20 | } 21 | 22 | export function main(options: Options) { 23 | console.log(options); 24 | const apiFileMap = getProto2ApiData(options); 25 | 26 | const result = genCode({ 27 | apiFileMap, 28 | apiName: options.apiName, 29 | apiPath: options.apiPath, 30 | apiPrefixPath: options.apiPrefixPath, 31 | }); 32 | 33 | for (const filePath in result) { 34 | outputFileSync(filePath, result[filePath], "utf8"); 35 | success(`${filePath} generated successfully`); 36 | console.log(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/hello.proto: -------------------------------------------------------------------------------- 1 | 2 | syntax = "proto3"; 3 | package hello; 4 | 5 | import "google/protobuf/empty.proto"; 6 | import "google/api/annotations.proto"; 7 | 8 | enum Status { 9 | UNKNOWN = 0; 10 | // 新创建 11 | NEW = 1; 12 | } 13 | 14 | message InfoReq { 15 | int32 id = 1 [proto3_optional = true]; // id 16 | string user_name = 2 ; // optional 17 | } 18 | message InfoResp { 19 | int32 ret_code = 1 [json_name = "retCode"]; 20 | string ret_msg = 2 [json_name = "retMsg"]; 21 | Status status = 3; 22 | } 23 | 24 | service API { 25 | rpc GetDemo(google.protobuf.Empty) returns (google.protobuf.Empty) { 26 | option (google.api.http) = { 27 | get: "/get" 28 | body: "*" 29 | }; 30 | } 31 | rpc PostDemo(InfoReq) returns (InfoResp) { 32 | option (google.api.http) = { 33 | post: "/post" 34 | }; 35 | } 36 | 37 | } 38 | 39 | 40 | message GetRequest { 41 | int64 id = 1; 42 | int64 external_id = 2; 43 | int32 external_type = 3; 44 | } 45 | 46 | service API2 { 47 | // @method get 48 | // @redirect api/get-game 49 | rpc GetGame(GetRequest) returns (InfoResp); 50 | rpc BatchGetGame(GetRequest) returns (InfoResp); 51 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "proto2api", 3 | "version": "0.0.8", 4 | "description": "Convert proto file to api file", 5 | "bin": { 6 | "proto2api": "./bin/index" 7 | }, 8 | "packageManager": "pnpm@6.32.3", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/yuexing0921/proto2api" 12 | }, 13 | "main": "dist/index.js", 14 | "types": "dist/index.d.js", 15 | "scripts": { 16 | "dev": "tsc --watch", 17 | "test": "jest", 18 | "build": "tsc" 19 | }, 20 | "keywords": [ 21 | "proto" 22 | ], 23 | "author": "yuexing ", 24 | "license": "MIT", 25 | "dependencies": { 26 | "chalk": "^4.1.0", 27 | "commander": "^9.0.0", 28 | "fs-extra": "^10.0.0", 29 | "glob": "^7.2.0", 30 | "prettier": "^2.5.1", 31 | "protobufjs": "^6.11.2", 32 | "ts-node": "^10.7.0" 33 | }, 34 | "devDependencies": { 35 | "@babel/core": "^7.17.7", 36 | "@babel/preset-env": "^7.16.11", 37 | "@babel/preset-typescript": "^7.16.7", 38 | "@types/chalk": "^2.2.0", 39 | "@types/commander": "^2.12.2", 40 | "@types/fs-extra": "^9.0.13", 41 | "@types/jest": "^27.4.1", 42 | "@types/prettier": "^2.4.3", 43 | "babel-jest": "^27.5.1", 44 | "jest": "^27.5.1", 45 | "typescript": "^4.5.4" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /common/google/api/annotations.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.api; 18 | 19 | import "google/api/http.proto"; 20 | import "google/protobuf/descriptor.proto"; 21 | 22 | option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; 23 | option php_namespace = "Bybit\\GTDMicro\\Stub\\Google\\Api\\Annotations"; 24 | option java_multiple_files = true; 25 | option java_outer_classname = "AnnotationsProto"; 26 | option java_package = "com.google.api"; 27 | option objc_class_prefix = "GAPI"; 28 | 29 | extend google.protobuf.MethodOptions { 30 | // See `HttpRule`. 31 | HttpRule http = 72295728; 32 | } 33 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 用于把proto文件转换成特定语言的api文件 2 | 3 | 1. 先把需要转换的proto文件确定好 4 | 2. 依次遍历proto文件,然后转换成ts文件 5 | 6 | 具体使用方式:https://www.yuque.com/yuexing0921/blog/ebmrh5 7 | 8 | ## 快速开始 9 | ``` bash 10 | npm install -g proto2api 11 | 12 | cd proto2api 13 | 14 | proto2api -d examples/hello.proto -o api 15 | ``` 16 | ## 命令行说明 17 | ``` 18 | Usage: proto2api [options] 19 | 20 | Convert proto file to api file 21 | 22 | Options: 23 | Options: 24 | -V, --version output the version number 25 | --debug load code with ts-node for debug 26 | -d, --dir directory address of Protocol Buffers. eq: /path/pbdir 27 | or /path/hello.proto 28 | -o, --output Output api path 29 | --protoDir The root directory for loading proto files. By default, 30 | the directory folder named proto3|proto2 will be found. 31 | If it still does not exist, it will try to find it 32 | automatically, but the correctness is not guaranteed. 33 | (default: "") 34 | --apiName apiName (default: "webapi") 35 | --apiPath apiPath (default: "~/utils/api") 36 | --prefix api prefix path (default: "") 37 | --depPath the address of the external dependency proto library. 38 | eq: /common/proto3 (default: "") 39 | --ignore [ignore...] ignore unnecessary generated pb files (default: 40 | "google|swagger") 41 | -h, --help display help for command 42 | -h, --help display help for command 43 | ``` 44 | ## 参考文档 45 | Google Protobuf 语法指南 https://developers.google.com/protocol-buffers/docs/proto3 -------------------------------------------------------------------------------- /examples/complex/svc.proto: -------------------------------------------------------------------------------- 1 | 2 | syntax = "proto3"; 3 | package complex; 4 | 5 | import "google/protobuf/empty.proto"; 6 | import "google/api/annotations.proto"; 7 | import "google/protobuf/api.proto"; 8 | import "enum/enum.proto"; 9 | 10 | enum Status { 11 | UNKNOWN = 0; 12 | NEW = 1; 13 | } 14 | 15 | 16 | message InfoReq { 17 | int32 id = 1; // id 18 | string user_name = 2 [json_name = "userName"]; 19 | // rely on its own message 20 | enum InlineStatus { 21 | UNKNOWN = 0; 22 | NEW = 1; 23 | } 24 | InlineStatus inlineStatus = 3; 25 | message InlineItem { 26 | string id = 1; 27 | } 28 | InlineItem item = 4; 29 | 30 | map map = 5; 31 | 32 | // Depends on the message of the current file 33 | Status status = 6; 34 | 35 | // Externally dependent messages 36 | google.protobuf.Method method = 7; 37 | 38 | // The externally introduced message has the same name as the current message 39 | enum.Status helloStatus = 8; 40 | 41 | } 42 | message InfoResp { 43 | int32 ret_code = 1 [json_name = "retCode"]; 44 | string ret_msg = 2 [json_name = "retMsg"]; 45 | Status status = 3; 46 | } 47 | 48 | service API { 49 | rpc GetDemo(google.protobuf.Empty) returns (InfoResp) { 50 | option (google.api.http) = { 51 | get: "/get" 52 | body: "*" 53 | }; 54 | } 55 | rpc PostDemo(InfoReq) returns (InfoResp) { 56 | option (google.api.http) = { 57 | post: "/post" 58 | }; 59 | } 60 | 61 | // asdfasdf 62 | // @redirect /v1/post 63 | // asdfasdf 64 | rpc RedirectDemo(InfoReq) returns (enum.InfoResp) { 65 | option (google.api.http) = { 66 | post: "/post" 67 | }; 68 | } 69 | } -------------------------------------------------------------------------------- /__tests__/swagger/core.test.ts: -------------------------------------------------------------------------------- 1 | import { trim } from "../_utils"; 2 | import { pathToName } from "../../src/swagger/core"; 3 | 4 | describe("core pathToName test", () => { 5 | test("An error is reported when path is null, undefined, or number", () => { 6 | expect(() => { 7 | pathToName(""); 8 | }).toThrow(); 9 | expect(() => { 10 | pathToName(undefined); 11 | }).toThrow(); 12 | expect(() => { 13 | pathToName(null); 14 | }).toThrow(); 15 | }); 16 | test("aabc => aabc", () => { 17 | const result = pathToName("aabc"); 18 | const expected = "aabc"; 19 | expect(result).toBe(expected); 20 | }); 21 | test("aa_1bc => aa1bc", () => { 22 | const result = pathToName("aa_1bc"); 23 | const expected = "aa1bc"; 24 | expect(result).toBe(expected); 25 | }); 26 | test("aa_bc => aaBc", () => { 27 | const result = pathToName("aa_bc"); 28 | const expected = "aaBc"; 29 | expect(result).toBe(expected); 30 | }); 31 | 32 | test("aa-bc => aaBc", () => { 33 | const result = pathToName("aa-bc"); 34 | const expected = "aaBc"; 35 | expect(result).toBe(expected); 36 | }); 37 | 38 | test("dd/aa-bc => aaBc", () => { 39 | const result = pathToName("dd/aa-bc"); 40 | const expected = "aaBc"; 41 | expect(result).toBe(expected); 42 | }); 43 | test("bb/dd/aa-bc => aaBc", () => { 44 | const result = pathToName("bb/dd/aa-bc"); 45 | const expected = "aaBc"; 46 | expect(result).toBe(expected); 47 | }); 48 | test("bb/dd/aa-bc-ee => aaBcEe", () => { 49 | const result = pathToName("bb/dd/aa-bc-ee"); 50 | const expected = "aaBcEe"; 51 | expect(result).toBe(expected); 52 | }); 53 | test("bb/dd/aa_bc => aaBc", () => { 54 | const result = pathToName("bb/dd/aa_bc"); 55 | const expected = "aaBc"; 56 | expect(result).toBe(expected); 57 | }); 58 | test("bb/dd/aa_bc_ee => aaBcEe", () => { 59 | const result = pathToName("bb/dd/aa_bc_ee"); 60 | const expected = "aaBcEe"; 61 | expect(result).toBe(expected); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /__tests__/genTsApi/renderEnum.test.ts: -------------------------------------------------------------------------------- 1 | import { trim } from "../_utils"; 2 | import { renderEnum } from "../../src/genTsApi"; 3 | 4 | describe("renderEnum test", () => { 5 | test("Normal number enum", () => { 6 | const list = [ 7 | { 8 | name: "Status", 9 | members: [ 10 | { 11 | name: "START", 12 | }, 13 | { 14 | name: "END", 15 | }, 16 | ], 17 | }, 18 | ]; 19 | const result = trim(renderEnum(list)); 20 | const expected = trim(` 21 | export enum Status { 22 | START, 23 | END 24 | } 25 | `); 26 | expect(result).toBe(expected); 27 | }); 28 | 29 | test("String enumeration", () => { 30 | const list = [ 31 | { 32 | name: "Status", 33 | members: [ 34 | { 35 | name: "START", 36 | initializer: "start", 37 | }, 38 | { 39 | name: "END", 40 | initializer: "end", 41 | }, 42 | ], 43 | }, 44 | ]; 45 | const result = trim(renderEnum(list)); 46 | const expected = trim(` 47 | export enum Status { 48 | START = 'start', 49 | END = 'end' 50 | } 51 | `); 52 | expect(result).toBe(expected); 53 | }); 54 | 55 | test("An enumeration with comments", () => { 56 | const list = [ 57 | { 58 | name: "Status", 59 | members: [ 60 | { 61 | name: "START", 62 | initializer: "start", 63 | comment: "status start", 64 | }, 65 | { 66 | name: "END", 67 | initializer: "end", 68 | comment: "status end", 69 | }, 70 | ], 71 | }, 72 | ]; 73 | const result = trim(renderEnum(list)); 74 | const expected = trim(` 75 | export enum Status { 76 | // status start 77 | START = 'start', 78 | // status end 79 | END = 'end' 80 | } 81 | `); 82 | expect(result).toBe(expected); 83 | }); 84 | }); 85 | -------------------------------------------------------------------------------- /__tests__/genTsApi/renderComment.test.ts: -------------------------------------------------------------------------------- 1 | import { renderImport } from "../../src/genTsApi"; 2 | import { trim } from "../_utils"; 3 | 4 | describe("renderImport test", () => { 5 | test("Single line rendering", () => { 6 | const imports = [ 7 | { 8 | importClause: [ 9 | { 10 | type: "A", 11 | }, 12 | { 13 | type: "B", 14 | }, 15 | { 16 | type: "C", 17 | }, 18 | ], 19 | moduleSpecifier: "~/moduleA", 20 | }, 21 | ]; 22 | const result = renderImport(imports, {}); 23 | const expected = `import { A,B,C } from '~/moduleA'`; 24 | expect(result).toBe(expected); 25 | }); 26 | 27 | test("Multi-line rendering", () => { 28 | const imports = [ 29 | { 30 | importClause: [ 31 | { 32 | type: "A", 33 | }, 34 | { 35 | type: "B", 36 | }, 37 | { 38 | type: "C", 39 | }, 40 | ], 41 | moduleSpecifier: "~/moduleA", 42 | }, 43 | { 44 | importClause: [ 45 | { 46 | type: "A", 47 | }, 48 | { 49 | type: "B", 50 | }, 51 | { 52 | type: "C", 53 | }, 54 | ], 55 | moduleSpecifier: "~/moduleB", 56 | }, 57 | ]; 58 | const result = trim(renderImport(imports, {})); 59 | const expected = trim(` 60 | import { A,B,C } from '~/moduleA' 61 | import { A,B,C } from '~/moduleB' 62 | `); 63 | expect(result).toBe(expected); 64 | }); 65 | 66 | test("Alias name test", () => { 67 | const imports = [ 68 | { 69 | importClause: [ 70 | { 71 | type: "A", 72 | dependencyTypeName: "xx.BB.A", 73 | }, 74 | { 75 | type: "B", 76 | }, 77 | { 78 | type: "C", 79 | }, 80 | ], 81 | moduleSpecifier: "~/moduleA", 82 | }, 83 | ]; 84 | const result = renderImport(imports, { A: 1 }); 85 | const expected = `import { A as XxBBA,B,C } from '~/moduleA'`; 86 | expect(result).toBe(expected); 87 | }); 88 | }); 89 | -------------------------------------------------------------------------------- /common/google/protobuf/source_context.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option java_package = "com.google.protobuf"; 37 | option java_outer_classname = "SourceContextProto"; 38 | option java_multiple_files = true; 39 | option objc_class_prefix = "GPB"; 40 | option go_package = "google.golang.org/genproto/protobuf/source_context;source_context"; 41 | 42 | // `SourceContext` represents information about the source of a 43 | // protobuf element, like the file in which it is defined. 44 | message SourceContext { 45 | // The path-qualified name of the .proto file that contained the associated 46 | // protobuf element. For example: `"google/protobuf/source_context.proto"`. 47 | string file_name = 1; 48 | } 49 | -------------------------------------------------------------------------------- /common/google/protobuf/empty.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option go_package = "github.com/golang/protobuf/ptypes/empty"; 37 | option java_package = "com.google.protobuf"; 38 | option java_outer_classname = "EmptyProto"; 39 | option java_multiple_files = true; 40 | option objc_class_prefix = "GPB"; 41 | option cc_enable_arenas = true; 42 | 43 | // A generic empty message that you can re-use to avoid defining duplicated 44 | // empty messages in your APIs. A typical example is to use it as the request 45 | // or the response type of an API method. For instance: 46 | // 47 | // service Foo { 48 | // rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); 49 | // } 50 | // 51 | // The JSON representation for `Empty` is empty JSON object `{}`. 52 | message Empty {} 53 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import chalk from "chalk"; 2 | import * as fse from "fs-extra"; 3 | import { existsSync } from "fs-extra"; 4 | import { join } from "path"; 5 | import { format as prettify } from "prettier"; 6 | 7 | export const error = (msg) => { 8 | console.log(chalk.red(msg)); 9 | }; 10 | 11 | export const warning = (msg) => { 12 | console.log(chalk.yellow(msg)); 13 | }; 14 | 15 | export const log = (msg) => { 16 | console.log(chalk.blue(msg)); 17 | }; 18 | 19 | export const success = (msg) => { 20 | console.log(chalk.green(msg)); 21 | }; 22 | 23 | export const writeFile = (writePath: string, data: string) => { 24 | return new Promise((resolve, reject) => { 25 | fse.writeFile(writePath, data, (err) => { 26 | if (err) { 27 | reject(err); 28 | } else { 29 | resolve(true); 30 | } 31 | }); 32 | }); 33 | }; 34 | 35 | export const isPrototype = (original: any, target: any) => { 36 | return Object.getPrototypeOf(original) === target.prototype; 37 | }; 38 | 39 | /** 40 | * 获取 pathB相对于pathA需要走多少步,才能找到对方 41 | * @param pathA 42 | * @param pathB 43 | * @param depth 44 | * @returns 45 | */ 46 | export function getRelativePathABDepth(pathA, pathB, depth = 0) { 47 | if (pathA.startsWith(pathB)) { 48 | const path = pathA.replace(pathB, "").slice(1); 49 | if (depth === 0) { 50 | return "./" + path; 51 | } else { 52 | return "../".repeat(depth) + path; 53 | } 54 | } else { 55 | return getRelativePathABDepth( 56 | pathA, 57 | pathB.match(/\//) ? pathB.slice(0, pathB.lastIndexOf("/")) : "", 58 | depth + 1 59 | ); 60 | } 61 | } 62 | 63 | export function format(code: string): string { 64 | const option = { 65 | printWidth: 80, 66 | singleQuote: true, 67 | semi: true, 68 | tabWidth: 2, 69 | insertPragma: true, 70 | bracketSpacing: true, 71 | useTabs: false, 72 | parser: "typescript", 73 | }; 74 | 75 | return prettify(code, option); 76 | } 77 | 78 | export const recursionDirFindPath = ( 79 | rootDir: string, 80 | target: string 81 | ): { 82 | path: string; 83 | target: string; 84 | } => { 85 | if (!target) { 86 | return { 87 | path: "", 88 | target, 89 | }; 90 | } 91 | const path = join(rootDir, target); 92 | if (existsSync(path)) { 93 | return { 94 | path, 95 | target: target.match(/^\//) ? target : "/" + target, 96 | }; 97 | } 98 | const arr = target.split("/"); 99 | arr.shift(); 100 | return recursionDirFindPath(rootDir, arr.join("/")); 101 | }; 102 | 103 | export const toHump = function (str: string, isBigHump = false): string { 104 | const a = str.split(/-|_|\./); 105 | let result = a[0]; 106 | for (let i = 1; i < a.length; i++) { 107 | result = result + a[i].slice(0, 1).toUpperCase() + a[i].slice(1); 108 | } 109 | if (isBigHump) { 110 | return result.replace(/^\S/, (sub) => sub.toUpperCase()); 111 | } 112 | return result; 113 | }; 114 | -------------------------------------------------------------------------------- /src/apiInterface.ts: -------------------------------------------------------------------------------- 1 | export interface Import { 2 | importClause: Array<{ 3 | type: string; 4 | dependencyTypeName?: string; 5 | }>; 6 | moduleSpecifier?: string; 7 | resolvedPath?: string; 8 | } 9 | 10 | export interface EnumMember { 11 | name: string; 12 | comment?: string; 13 | initializer?: string | number; 14 | } 15 | 16 | export interface Enum { 17 | name: string; 18 | comment?: string; 19 | members: EnumMember[]; 20 | } 21 | // The type of the dependent element in the message 22 | export enum DependencyType { 23 | // message Info{ 24 | // int32 code = 1; 25 | // enum Item { 26 | // xxx = 1; 27 | // } 28 | // Item item = 2; 29 | // } 30 | INLINE = "inline", 31 | 32 | // message Info{ 33 | // int32 code = 1; 34 | // google.protobuf.Method method = 2; 35 | // } 36 | EXTERNAL = "external", 37 | 38 | // message Item{ 39 | // string id = 1; 40 | // } 41 | // message Info{ 42 | // int32 code = 1; 43 | // Item item = 2; 44 | // } 45 | CURRENT = "current", 46 | 47 | // message Info{ 48 | // int32 code = 1; 49 | // } 50 | SYSTEM = "system", 51 | } 52 | 53 | export interface PropertyType { 54 | type: string; 55 | dependencyType?: DependencyType; // default 'system' 56 | dependencyTypeName?: string; // eq: google.protobuf.Empty. Only has value if DependencyType.EXTERNAL 57 | // If there is an external reference file, 58 | // the referenced file address will be written 59 | resolvedPath?: string; 60 | aliasName?: string; // 61 | 62 | // map 63 | map?: boolean; 64 | keyType?: string; 65 | } 66 | 67 | export interface PropertySignature { 68 | name: string; 69 | comment?: string; 70 | propertyType: PropertyType; 71 | 72 | // arr[] 73 | repeated?: boolean; 74 | 75 | optional?: boolean; 76 | defaultValue?: boolean; 77 | jsonName?: string; 78 | } 79 | 80 | export interface InterfaceModule { 81 | comment?: string; 82 | name: string; 83 | enums: Enum[]; 84 | interfaces: Interface[]; 85 | } 86 | 87 | export interface Interface { 88 | name: string; 89 | comment?: string; 90 | members: PropertySignature[]; 91 | module?: InterfaceModule; 92 | } 93 | 94 | export interface ApiModule { 95 | comment?: string; 96 | name: string; 97 | functions: ApiFunction[]; 98 | } 99 | export interface ApiFunction { 100 | name: string; 101 | comment?: string; 102 | req: PropertyType; 103 | url: string; 104 | redirectUrl?: string; 105 | res: PropertyType; 106 | method: "get" | "post" | "put" | "patch" | "delete"; 107 | } 108 | 109 | export interface ApiFile { 110 | protoPath: string; // proto file path 111 | protoTargetPath: string; // proto target file path 112 | outputPath: string; // generated path 113 | apiPrefixPath: string; 114 | comment?: string; // comment in the header 115 | imports: Import[]; // referenced external dependencies 116 | enums: Enum[]; // all enums 117 | interfaces: Interface[]; // all interfaces 118 | apiModules: ApiModule[]; // 119 | } 120 | -------------------------------------------------------------------------------- /__tests__/utils.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | toHump, 3 | recursionDirFindPath, 4 | getRelativePathABDepth, 5 | } from "../src/utils"; 6 | 7 | describe("getRelativePathABDepth tests", () => { 8 | test("one layer cycle", () => { 9 | const result = getRelativePathABDepth("/a/b/c", "/b"); 10 | const expected = "../a/b/c"; 11 | expect(result).toBe(expected); 12 | }); 13 | test("two layer cycle", () => { 14 | const result = getRelativePathABDepth("/a/b/c", "/b/c"); 15 | const expected = "../../a/b/c"; 16 | expect(result).toBe(expected); 17 | }); 18 | }); 19 | 20 | describe("toHump test", () => { 21 | test("aabc => aabc", () => { 22 | const result = toHump("aabc"); 23 | const expected = "aabc"; 24 | expect(result).toBe(expected); 25 | }); 26 | test("aa_1bc => aa1bc", () => { 27 | const result = toHump("aa_1bc"); 28 | const expected = "aa1bc"; 29 | expect(result).toBe(expected); 30 | }); 31 | test("aa_bc => aaBc", () => { 32 | const result = toHump("aa_bc"); 33 | const expected = "aaBc"; 34 | expect(result).toBe(expected); 35 | }); 36 | test("aa_bc_ee => aaBcEe", () => { 37 | const result = toHump("aa_bc_ee"); 38 | const expected = "aaBcEe"; 39 | expect(result).toBe(expected); 40 | }); 41 | 42 | test("aa-bc => aaBc", () => { 43 | const result = toHump("aa-bc"); 44 | const expected = "aaBc"; 45 | expect(result).toBe(expected); 46 | }); 47 | test("aa-bc-dd => aaBcDd", () => { 48 | const result = toHump("aa-bc-dd"); 49 | const expected = "aaBcDd"; 50 | expect(result).toBe(expected); 51 | }); 52 | 53 | test("aa-bc-dd big hump => AaBcDd", () => { 54 | const result = toHump("aa-bc-dd", true); 55 | const expected = "AaBcDd"; 56 | expect(result).toBe(expected); 57 | }); 58 | test("aa.bc => aaBc", () => { 59 | const result = toHump("aa.bc"); 60 | const expected = "aaBc"; 61 | expect(result).toBe(expected); 62 | }); 63 | test("aa.bc.dd => aaBcDd", () => { 64 | const result = toHump("aa.bc.dd"); 65 | const expected = "aaBcDd"; 66 | expect(result).toBe(expected); 67 | }); 68 | 69 | test("aa.bc.dd big hump => AaBcDd", () => { 70 | const result = toHump("aa.bc.dd", true); 71 | const expected = "AaBcDd"; 72 | expect(result).toBe(expected); 73 | }); 74 | }); 75 | 76 | describe("recursionDirFindPath tests", () => { 77 | test("path does not exist", () => { 78 | const result = recursionDirFindPath("aa-bc-dd", "/path"); 79 | const expected = { 80 | path: "", 81 | target: "", 82 | }; 83 | expect(result).toEqual(expected); 84 | }); 85 | 86 | test("when the path exists", () => { 87 | const result = recursionDirFindPath(process.cwd(), "/__tests__"); 88 | const expected = { 89 | target: "/__tests__", 90 | path: expect.stringMatching(/__tests__/), 91 | }; 92 | expect(result).toMatchObject(expected); 93 | }); 94 | 95 | test("relative path", () => { 96 | const result = recursionDirFindPath(__dirname, "/__tests__/utils.test.ts"); 97 | const expected = { 98 | target: "/utils.test.ts", 99 | path: expect.stringMatching(/__tests__/), 100 | }; 101 | expect(result).toMatchObject(expected); 102 | }); 103 | }); 104 | -------------------------------------------------------------------------------- /bin/index: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict"; 3 | const { Command } = require("commander"); // include commander in git clone of commander repo 4 | const path = require("path"); 5 | const fse = require("fs-extra"); 6 | const { Glob } = require("glob"); 7 | const pkg = require("../package.json"); 8 | const resolve = (p) => path.resolve(p); 9 | const program = new Command(); 10 | 11 | program 12 | .version(pkg.version) 13 | .option("--debug", "load code with ts-node for debug") 14 | .requiredOption( 15 | "-d, --dir ", 16 | "directory address of Protocol Buffers. eq: /path/pbdir or /path/hello.proto" 17 | ) 18 | .requiredOption("-o, --output ", "Output api path") 19 | .option( 20 | "--protoDir ", 21 | "The root directory for loading proto files. By default, the directory folder named proto3|proto2 will be found. If it still does not exist, it will try to find it automatically, but the correctness is not guaranteed.", 22 | "" 23 | ) 24 | .option("--apiName ", "apiName", "webapi") 25 | .option("--apiPath ", "apiPath", "~/utils/api") 26 | .option("--prefix ", "api prefix path", "") 27 | .option( 28 | "--depPath ", 29 | "the address of the external dependency proto library. eq: /common/proto3", 30 | "" 31 | ) 32 | .option( 33 | "--ignore [ignore...]", 34 | "ignore unnecessary generated pb files", 35 | "google|swagger" 36 | ) 37 | .description(pkg.description) 38 | .action(async (opt) => { 39 | const dirPath = resolve(opt.dir); 40 | if (!fse.existsSync(dirPath)) { 41 | console.error(`The address ${dirPath} does not exist`); 42 | return process.exit(1); 43 | } 44 | let files = []; 45 | if (opt.dir.endsWith(".proto")) { 46 | files.push(dirPath); 47 | } else { 48 | files = await getPathsDir(dirPath + "/**/*.proto"); 49 | } 50 | if (files.length === 0) { 51 | console.error( 52 | `The corresponding proto file was not found under the ${dirPath}` 53 | ); 54 | return process.exit(1); 55 | } 56 | 57 | let protoDir = opt.protoDir || ""; 58 | if (!protoDir) { 59 | const result = files[0].match(/\S*proto[2|3]{1}/); 60 | protoDir = result ? result[0] : ""; 61 | } 62 | 63 | const devMode = opt.debug; 64 | 65 | const output = resolve(opt.output); 66 | 67 | let ignore; 68 | if (typeof opt.ignore === "string") { 69 | ignore = new RegExp(opt.ignore); 70 | } else { 71 | ignore = 72 | opt.ignore && opt.ignore.join ? new RegExp(opt.ignore.join("|")) : null; 73 | } 74 | 75 | const options = { 76 | files, 77 | output: output.endsWith("/") ? output : output + "/", 78 | apiName: opt.apiName, 79 | apiPath: opt.apiPath, 80 | apiPrefixPath: opt.prefix, 81 | protoDir: resolve(protoDir), 82 | depPath: opt.depPath, 83 | ignore, 84 | }; 85 | 86 | if (devMode) { 87 | require("ts-node").register({ 88 | project: `${__dirname}/../tsconfig.spec.json`, 89 | }); 90 | const { main } = require(`${__dirname}/../src/index`); 91 | main(options); 92 | } else { 93 | const { main } = require(`${__dirname}/../dist/index`); 94 | main(options); 95 | } 96 | }); 97 | 98 | program.parse(); 99 | 100 | function getPathsDir(dir) { 101 | return new Promise((resolve, reject) => { 102 | new Glob(dir, { mark: true, sync: false }, (err, files) => { 103 | if (err) { 104 | console.error("Glob error: ", err); 105 | return reject(err); 106 | } 107 | resolve(files); 108 | }); 109 | }); 110 | } 111 | -------------------------------------------------------------------------------- /common/google/protobuf/struct.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option cc_enable_arenas = true; 37 | option go_package = "github.com/golang/protobuf/ptypes/struct;structpb"; 38 | option java_package = "com.google.protobuf"; 39 | option java_outer_classname = "StructProto"; 40 | option java_multiple_files = true; 41 | option objc_class_prefix = "GPB"; 42 | 43 | // `Struct` represents a structured data value, consisting of fields 44 | // which map to dynamically typed values. In some languages, `Struct` 45 | // might be supported by a native representation. For example, in 46 | // scripting languages like JS a struct is represented as an 47 | // object. The details of that representation are described together 48 | // with the proto support for the language. 49 | // 50 | // The JSON representation for `Struct` is JSON object. 51 | message Struct { 52 | // Unordered map of dynamically typed values. 53 | map fields = 1; 54 | } 55 | 56 | // `Value` represents a dynamically typed value which can be either 57 | // null, a number, a string, a boolean, a recursive struct value, or a 58 | // list of values. A producer of value is expected to set one of that 59 | // variants, absence of any variant indicates an error. 60 | // 61 | // The JSON representation for `Value` is JSON value. 62 | message Value { 63 | // The kind of value. 64 | oneof kind { 65 | // Represents a null value. 66 | NullValue null_value = 1; 67 | // Represents a double value. 68 | double number_value = 2; 69 | // Represents a string value. 70 | string string_value = 3; 71 | // Represents a boolean value. 72 | bool bool_value = 4; 73 | // Represents a structured value. 74 | Struct struct_value = 5; 75 | // Represents a repeated `Value`. 76 | ListValue list_value = 6; 77 | } 78 | } 79 | 80 | // `NullValue` is a singleton enumeration to represent the null value for the 81 | // `Value` type union. 82 | // 83 | // The JSON representation for `NullValue` is JSON `null`. 84 | enum NullValue { 85 | // Null value. 86 | NULL_VALUE = 0; 87 | } 88 | 89 | // `ListValue` is a wrapper around a repeated field of values. 90 | // 91 | // The JSON representation for `ListValue` is JSON array. 92 | message ListValue { 93 | // Repeated field of dynamically typed values. 94 | repeated Value values = 1; 95 | } 96 | -------------------------------------------------------------------------------- /common/google/rpc/status.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.rpc; 18 | 19 | import "google/protobuf/any.proto"; 20 | 21 | option go_package = "google.golang.org/genproto/googleapis/rpc/status;status"; 22 | option java_multiple_files = true; 23 | option java_outer_classname = "StatusProto"; 24 | option java_package = "com.google.rpc"; 25 | option objc_class_prefix = "RPC"; 26 | 27 | 28 | // The `Status` type defines a logical error model that is suitable for different 29 | // programming environments, including REST APIs and RPC APIs. It is used by 30 | // [gRPC](https://github.com/grpc). The error model is designed to be: 31 | // 32 | // - Simple to use and understand for most users 33 | // - Flexible enough to meet unexpected needs 34 | // 35 | // # Overview 36 | // 37 | // The `Status` message contains three pieces of data: error code, error message, 38 | // and error details. The error code should be an enum value of 39 | // [google.rpc.Code][google.rpc.Code], but it may accept additional error codes if needed. The 40 | // error message should be a developer-facing English message that helps 41 | // developers *understand* and *resolve* the error. If a localized user-facing 42 | // error message is needed, put the localized message in the error details or 43 | // localize it in the client. The optional error details may contain arbitrary 44 | // information about the error. There is a predefined set of error detail types 45 | // in the package `google.rpc` that can be used for common error conditions. 46 | // 47 | // # Language mapping 48 | // 49 | // The `Status` message is the logical representation of the error model, but it 50 | // is not necessarily the actual wire format. When the `Status` message is 51 | // exposed in different client libraries and different wire protocols, it can be 52 | // mapped differently. For example, it will likely be mapped to some exceptions 53 | // in Java, but more likely mapped to some error codes in C. 54 | // 55 | // # Other uses 56 | // 57 | // The error model and the `Status` message can be used in a variety of 58 | // environments, either with or without APIs, to provide a 59 | // consistent developer experience across different environments. 60 | // 61 | // Example uses of this error model include: 62 | // 63 | // - Partial errors. If a service needs to return partial errors to the client, 64 | // it may embed the `Status` in the normal response to indicate the partial 65 | // errors. 66 | // 67 | // - Workflow errors. A typical workflow has multiple steps. Each step may 68 | // have a `Status` message for error reporting. 69 | // 70 | // - Batch operations. If a client uses batch request and batch response, the 71 | // `Status` message should be used directly inside batch response, one for 72 | // each error sub-response. 73 | // 74 | // - Asynchronous operations. If an API call embeds asynchronous operation 75 | // results in its response, the status of those operations should be 76 | // represented directly using the `Status` message. 77 | // 78 | // - Logging. If some API errors are stored in logs, the message `Status` could 79 | // be used directly after any stripping needed for security/privacy reasons. 80 | message Status { 81 | // The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. 82 | int32 code = 1; 83 | 84 | // A developer-facing error message, which should be in English. Any 85 | // user-facing error message should be localized and sent in the 86 | // [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. 87 | string message = 2; 88 | 89 | // A list of messages that carry the error details. There is a common set of 90 | // message types for APIs to use. 91 | repeated google.protobuf.Any details = 3; 92 | } 93 | -------------------------------------------------------------------------------- /common/google/protobuf/wrappers.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | // Wrappers for primitive (non-message) types. These types are useful 32 | // for embedding primitives in the `google.protobuf.Any` type and for places 33 | // where we need to distinguish between the absence of a primitive 34 | // typed field and its default value. 35 | // 36 | // These wrappers have no meaningful use within repeated fields as they lack 37 | // the ability to detect presence on individual elements. 38 | // These wrappers have no meaningful use within a map or a oneof since 39 | // individual entries of a map or fields of a oneof can already detect presence. 40 | 41 | syntax = "proto3"; 42 | 43 | package google.protobuf; 44 | 45 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 46 | option cc_enable_arenas = true; 47 | option go_package = "github.com/golang/protobuf/ptypes/wrappers"; 48 | option java_package = "com.google.protobuf"; 49 | option java_outer_classname = "WrappersProto"; 50 | option java_multiple_files = true; 51 | option objc_class_prefix = "GPB"; 52 | 53 | // Wrapper message for `double`. 54 | // 55 | // The JSON representation for `DoubleValue` is JSON number. 56 | message DoubleValue { 57 | // The double value. 58 | double value = 1; 59 | } 60 | 61 | // Wrapper message for `float`. 62 | // 63 | // The JSON representation for `FloatValue` is JSON number. 64 | message FloatValue { 65 | // The float value. 66 | float value = 1; 67 | } 68 | 69 | // Wrapper message for `int64`. 70 | // 71 | // The JSON representation for `Int64Value` is JSON string. 72 | message Int64Value { 73 | // The int64 value. 74 | int64 value = 1; 75 | } 76 | 77 | // Wrapper message for `uint64`. 78 | // 79 | // The JSON representation for `UInt64Value` is JSON string. 80 | message UInt64Value { 81 | // The uint64 value. 82 | uint64 value = 1; 83 | } 84 | 85 | // Wrapper message for `int32`. 86 | // 87 | // The JSON representation for `Int32Value` is JSON number. 88 | message Int32Value { 89 | // The int32 value. 90 | int32 value = 1; 91 | } 92 | 93 | // Wrapper message for `uint32`. 94 | // 95 | // The JSON representation for `UInt32Value` is JSON number. 96 | message UInt32Value { 97 | // The uint32 value. 98 | uint32 value = 1; 99 | } 100 | 101 | // Wrapper message for `bool`. 102 | // 103 | // The JSON representation for `BoolValue` is JSON `true` and `false`. 104 | message BoolValue { 105 | // The bool value. 106 | bool value = 1; 107 | } 108 | 109 | // Wrapper message for `string`. 110 | // 111 | // The JSON representation for `StringValue` is JSON string. 112 | message StringValue { 113 | // The string value. 114 | string value = 1; 115 | } 116 | 117 | // Wrapper message for `bytes`. 118 | // 119 | // The JSON representation for `BytesValue` is JSON string. 120 | message BytesValue { 121 | // The bytes value. 122 | bytes value = 1; 123 | } 124 | -------------------------------------------------------------------------------- /common/google/protobuf/duration.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option cc_enable_arenas = true; 37 | option go_package = "github.com/golang/protobuf/ptypes/duration"; 38 | option java_package = "com.google.protobuf"; 39 | option java_outer_classname = "DurationProto"; 40 | option java_multiple_files = true; 41 | option objc_class_prefix = "GPB"; 42 | 43 | // A Duration represents a signed, fixed-length span of time represented 44 | // as a count of seconds and fractions of seconds at nanosecond 45 | // resolution. It is independent of any calendar and concepts like "day" 46 | // or "month". It is related to Timestamp in that the difference between 47 | // two Timestamp values is a Duration and it can be added or subtracted 48 | // from a Timestamp. Range is approximately +-10,000 years. 49 | // 50 | // # Examples 51 | // 52 | // Example 1: Compute Duration from two Timestamps in pseudo code. 53 | // 54 | // Timestamp start = ...; 55 | // Timestamp end = ...; 56 | // Duration duration = ...; 57 | // 58 | // duration.seconds = end.seconds - start.seconds; 59 | // duration.nanos = end.nanos - start.nanos; 60 | // 61 | // if (duration.seconds < 0 && duration.nanos > 0) { 62 | // duration.seconds += 1; 63 | // duration.nanos -= 1000000000; 64 | // } else if (durations.seconds > 0 && duration.nanos < 0) { 65 | // duration.seconds -= 1; 66 | // duration.nanos += 1000000000; 67 | // } 68 | // 69 | // Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. 70 | // 71 | // Timestamp start = ...; 72 | // Duration duration = ...; 73 | // Timestamp end = ...; 74 | // 75 | // end.seconds = start.seconds + duration.seconds; 76 | // end.nanos = start.nanos + duration.nanos; 77 | // 78 | // if (end.nanos < 0) { 79 | // end.seconds -= 1; 80 | // end.nanos += 1000000000; 81 | // } else if (end.nanos >= 1000000000) { 82 | // end.seconds += 1; 83 | // end.nanos -= 1000000000; 84 | // } 85 | // 86 | // Example 3: Compute Duration from datetime.timedelta in Python. 87 | // 88 | // td = datetime.timedelta(days=3, minutes=10) 89 | // duration = Duration() 90 | // duration.FromTimedelta(td) 91 | // 92 | // # JSON Mapping 93 | // 94 | // In JSON format, the Duration type is encoded as a string rather than an 95 | // object, where the string ends in the suffix "s" (indicating seconds) and 96 | // is preceded by the number of seconds, with nanoseconds expressed as 97 | // fractional seconds. For example, 3 seconds with 0 nanoseconds should be 98 | // encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should 99 | // be expressed in JSON format as "3.000000001s", and 3 seconds and 1 100 | // microsecond should be expressed in JSON format as "3.000001s". 101 | // 102 | // 103 | message Duration { 104 | // Signed seconds of the span of time. Must be from -315,576,000,000 105 | // to +315,576,000,000 inclusive. Note: these bounds are computed from: 106 | // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years 107 | int64 seconds = 1; 108 | 109 | // Signed fractions of a second at nanosecond resolution of the span 110 | // of time. Durations less than one second are represented with a 0 111 | // `seconds` field and a positive or negative `nanos` field. For durations 112 | // of one second or more, a non-zero value for the `nanos` field must be 113 | // of the same sign as the `seconds` field. Must be from -999,999,999 114 | // to +999,999,999 inclusive. 115 | int32 nanos = 2; 116 | } 117 | -------------------------------------------------------------------------------- /common/google/protobuf/any.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option go_package = "github.com/golang/protobuf/ptypes/any"; 37 | option java_package = "com.google.protobuf"; 38 | option java_outer_classname = "AnyProto"; 39 | option java_multiple_files = true; 40 | option objc_class_prefix = "GPB"; 41 | 42 | // `Any` contains an arbitrary serialized protocol buffer message along with a 43 | // URL that describes the type of the serialized message. 44 | // 45 | // Protobuf library provides support to pack/unpack Any values in the form 46 | // of utility functions or additional generated methods of the Any type. 47 | // 48 | // Example 1: Pack and unpack a message in C++. 49 | // 50 | // Foo foo = ...; 51 | // Any any; 52 | // any.PackFrom(foo); 53 | // ... 54 | // if (any.UnpackTo(&foo)) { 55 | // ... 56 | // } 57 | // 58 | // Example 2: Pack and unpack a message in Java. 59 | // 60 | // Foo foo = ...; 61 | // Any any = Any.pack(foo); 62 | // ... 63 | // if (any.is(Foo.class)) { 64 | // foo = any.unpack(Foo.class); 65 | // } 66 | // 67 | // Example 3: Pack and unpack a message in Python. 68 | // 69 | // foo = Foo(...) 70 | // any = Any() 71 | // any.Pack(foo) 72 | // ... 73 | // if any.Is(Foo.DESCRIPTOR): 74 | // any.Unpack(foo) 75 | // ... 76 | // 77 | // Example 4: Pack and unpack a message in Go 78 | // 79 | // foo := &pb.Foo{...} 80 | // any, err := ptypes.MarshalAny(foo) 81 | // ... 82 | // foo := &pb.Foo{} 83 | // if err := ptypes.UnmarshalAny(any, foo); err != nil { 84 | // ... 85 | // } 86 | // 87 | // The pack methods provided by protobuf library will by default use 88 | // 'type.googleapis.com/full.type.name' as the type URL and the unpack 89 | // methods only use the fully qualified type name after the last '/' 90 | // in the type URL, for example "foo.bar.com/x/y.z" will yield type 91 | // name "y.z". 92 | // 93 | // 94 | // JSON 95 | // ==== 96 | // The JSON representation of an `Any` value uses the regular 97 | // representation of the deserialized, embedded message, with an 98 | // additional field `@type` which contains the type URL. Example: 99 | // 100 | // package google.profile; 101 | // message Person { 102 | // string first_name = 1; 103 | // string last_name = 2; 104 | // } 105 | // 106 | // { 107 | // "@type": "type.googleapis.com/google.profile.Person", 108 | // "firstName": , 109 | // "lastName": 110 | // } 111 | // 112 | // If the embedded message type is well-known and has a custom JSON 113 | // representation, that representation will be embedded adding a field 114 | // `value` which holds the custom JSON in addition to the `@type` 115 | // field. Example (for message [google.protobuf.Duration][]): 116 | // 117 | // { 118 | // "@type": "type.googleapis.com/google.protobuf.Duration", 119 | // "value": "1.212s" 120 | // } 121 | // 122 | message Any { 123 | // A URL/resource name that uniquely identifies the type of the serialized 124 | // protocol buffer message. This string must contain at least 125 | // one "/" character. The last segment of the URL's path must represent 126 | // the fully qualified name of the type (as in 127 | // `path/google.protobuf.Duration`). The name should be in a canonical form 128 | // (e.g., leading "." is not accepted). 129 | // 130 | // In practice, teams usually precompile into the binary all types that they 131 | // expect it to use in the context of Any. However, for URLs which use the 132 | // scheme `http`, `https`, or no scheme, one can optionally set up a type 133 | // server that maps type URLs to message definitions as follows: 134 | // 135 | // * If no scheme is provided, `https` is assumed. 136 | // * An HTTP GET on the URL must yield a [google.protobuf.Type][] 137 | // value in binary format, or produce an error. 138 | // * Applications are allowed to cache lookup results based on the 139 | // URL, or have them precompiled into a binary to avoid any 140 | // lookup. Therefore, binary compatibility needs to be preserved 141 | // on changes to types. (Use versioned type names to manage 142 | // breaking changes.) 143 | // 144 | // Note: this functionality is not currently available in the official 145 | // protobuf release, and it is not used for type URLs beginning with 146 | // type.googleapis.com. 147 | // 148 | // Schemes other than `http`, `https` (or the empty scheme) might be 149 | // used with implementation specific semantics. 150 | // 151 | string type_url = 1; 152 | 153 | // Must be a valid serialized protocol buffer of the above specified type. 154 | bytes value = 2; 155 | } 156 | -------------------------------------------------------------------------------- /common/google/protobuf/timestamp.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option cc_enable_arenas = true; 37 | option go_package = "github.com/golang/protobuf/ptypes/timestamp"; 38 | option java_package = "com.google.protobuf"; 39 | option java_outer_classname = "TimestampProto"; 40 | option java_multiple_files = true; 41 | option objc_class_prefix = "GPB"; 42 | 43 | // A Timestamp represents a point in time independent of any time zone or local 44 | // calendar, encoded as a count of seconds and fractions of seconds at 45 | // nanosecond resolution. The count is relative to an epoch at UTC midnight on 46 | // January 1, 1970, in the proleptic Gregorian calendar which extends the 47 | // Gregorian calendar backwards to year one. 48 | // 49 | // All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap 50 | // second table is needed for interpretation, using a [24-hour linear 51 | // smear](https://developers.google.com/time/smear). 52 | // 53 | // The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By 54 | // restricting to that range, we ensure that we can convert to and from [RFC 55 | // 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. 56 | // 57 | // # Examples 58 | // 59 | // Example 1: Compute Timestamp from POSIX `time()`. 60 | // 61 | // Timestamp timestamp; 62 | // timestamp.set_seconds(time(NULL)); 63 | // timestamp.set_nanos(0); 64 | // 65 | // Example 2: Compute Timestamp from POSIX `gettimeofday()`. 66 | // 67 | // struct timeval tv; 68 | // gettimeofday(&tv, NULL); 69 | // 70 | // Timestamp timestamp; 71 | // timestamp.set_seconds(tv.tv_sec); 72 | // timestamp.set_nanos(tv.tv_usec * 1000); 73 | // 74 | // Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. 75 | // 76 | // FILETIME ft; 77 | // GetSystemTimeAsFileTime(&ft); 78 | // UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; 79 | // 80 | // // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z 81 | // // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. 82 | // Timestamp timestamp; 83 | // timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); 84 | // timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); 85 | // 86 | // Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. 87 | // 88 | // long millis = System.currentTimeMillis(); 89 | // 90 | // Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) 91 | // .setNanos((int) ((millis % 1000) * 1000000)).build(); 92 | // 93 | // 94 | // Example 5: Compute Timestamp from current time in Python. 95 | // 96 | // timestamp = Timestamp() 97 | // timestamp.GetCurrentTime() 98 | // 99 | // # JSON Mapping 100 | // 101 | // In JSON format, the Timestamp type is encoded as a string in the 102 | // [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the 103 | // format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" 104 | // where {year} is always expressed using four digits while {month}, {day}, 105 | // {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional 106 | // seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), 107 | // are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone 108 | // is required. A proto3 JSON serializer should always use UTC (as indicated by 109 | // "Z") when printing the Timestamp type and a proto3 JSON parser should be 110 | // able to accept both UTC and other timezones (as indicated by an offset). 111 | // 112 | // For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 113 | // 01:30 UTC on January 15, 2017. 114 | // 115 | // In JavaScript, one can convert a Date object to this format using the 116 | // standard 117 | // [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) 118 | // method. In Python, a standard `datetime.datetime` object can be converted 119 | // to this format using 120 | // [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with 121 | // the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use 122 | // the Joda Time's [`ISODateTimeFormat.dateTime()`]( 123 | // http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D 124 | // ) to obtain a formatter capable of generating timestamps in this format. 125 | // 126 | // 127 | message Timestamp { 128 | // Represents seconds of UTC time since Unix epoch 129 | // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to 130 | // 9999-12-31T23:59:59Z inclusive. 131 | int64 seconds = 1; 132 | 133 | // Non-negative fractions of a second at nanosecond resolution. Negative 134 | // second values with fractions must still have non-negative nanos values 135 | // that count forward in time. Must be from 0 to 999,999,999 136 | // inclusive. 137 | int32 nanos = 2; 138 | } 139 | -------------------------------------------------------------------------------- /common/google/protobuf/type.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | import "google/protobuf/any.proto"; 36 | import "google/protobuf/source_context.proto"; 37 | 38 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 39 | option cc_enable_arenas = true; 40 | option java_package = "com.google.protobuf"; 41 | option java_outer_classname = "TypeProto"; 42 | option java_multiple_files = true; 43 | option objc_class_prefix = "GPB"; 44 | option go_package = "google.golang.org/genproto/protobuf/ptype;ptype"; 45 | 46 | // A protocol buffer message type. 47 | message Type { 48 | // The fully qualified message name. 49 | string name = 1; 50 | // The list of fields. 51 | repeated Field fields = 2; 52 | // The list of types appearing in `oneof` definitions in this type. 53 | repeated string oneofs = 3; 54 | // The protocol buffer options. 55 | repeated Option options = 4; 56 | // The source context. 57 | SourceContext source_context = 5; 58 | // The source syntax. 59 | Syntax syntax = 6; 60 | } 61 | 62 | // A single field of a message type. 63 | message Field { 64 | // Basic field types. 65 | enum Kind { 66 | // Field type unknown. 67 | TYPE_UNKNOWN = 0; 68 | // Field type double. 69 | TYPE_DOUBLE = 1; 70 | // Field type float. 71 | TYPE_FLOAT = 2; 72 | // Field type int64. 73 | TYPE_INT64 = 3; 74 | // Field type uint64. 75 | TYPE_UINT64 = 4; 76 | // Field type int32. 77 | TYPE_INT32 = 5; 78 | // Field type fixed64. 79 | TYPE_FIXED64 = 6; 80 | // Field type fixed32. 81 | TYPE_FIXED32 = 7; 82 | // Field type bool. 83 | TYPE_BOOL = 8; 84 | // Field type string. 85 | TYPE_STRING = 9; 86 | // Field type group. Proto2 syntax only, and deprecated. 87 | TYPE_GROUP = 10; 88 | // Field type message. 89 | TYPE_MESSAGE = 11; 90 | // Field type bytes. 91 | TYPE_BYTES = 12; 92 | // Field type uint32. 93 | TYPE_UINT32 = 13; 94 | // Field type enum. 95 | TYPE_ENUM = 14; 96 | // Field type sfixed32. 97 | TYPE_SFIXED32 = 15; 98 | // Field type sfixed64. 99 | TYPE_SFIXED64 = 16; 100 | // Field type sint32. 101 | TYPE_SINT32 = 17; 102 | // Field type sint64. 103 | TYPE_SINT64 = 18; 104 | } 105 | 106 | // Whether a field is optional, required, or repeated. 107 | enum Cardinality { 108 | // For fields with unknown cardinality. 109 | CARDINALITY_UNKNOWN = 0; 110 | // For optional fields. 111 | CARDINALITY_OPTIONAL = 1; 112 | // For required fields. Proto2 syntax only. 113 | CARDINALITY_REQUIRED = 2; 114 | // For repeated fields. 115 | CARDINALITY_REPEATED = 3; 116 | }; 117 | 118 | // The field type. 119 | Kind kind = 1; 120 | // The field cardinality. 121 | Cardinality cardinality = 2; 122 | // The field number. 123 | int32 number = 3; 124 | // The field name. 125 | string name = 4; 126 | // The field type URL, without the scheme, for message or enumeration 127 | // types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. 128 | string type_url = 6; 129 | // The index of the field type in `Type.oneofs`, for message or enumeration 130 | // types. The first type has index 1; zero means the type is not in the list. 131 | int32 oneof_index = 7; 132 | // Whether to use alternative packed wire representation. 133 | bool packed = 8; 134 | // The protocol buffer options. 135 | repeated Option options = 9; 136 | // The field JSON name. 137 | string json_name = 10; 138 | // The string value of the default value of this field. Proto2 syntax only. 139 | string default_value = 11; 140 | } 141 | 142 | // Enum type definition. 143 | message Enum { 144 | // Enum type name. 145 | string name = 1; 146 | // Enum value definitions. 147 | repeated EnumValue enumvalue = 2; 148 | // Protocol buffer options. 149 | repeated Option options = 3; 150 | // The source context. 151 | SourceContext source_context = 4; 152 | // The source syntax. 153 | Syntax syntax = 5; 154 | } 155 | 156 | // Enum value definition. 157 | message EnumValue { 158 | // Enum value name. 159 | string name = 1; 160 | // Enum value number. 161 | int32 number = 2; 162 | // Protocol buffer options. 163 | repeated Option options = 3; 164 | } 165 | 166 | // A protocol buffer option, which can be attached to a message, field, 167 | // enumeration, etc. 168 | message Option { 169 | // The option's name. For protobuf built-in options (options defined in 170 | // descriptor.proto), this is the short name. For example, `"map_entry"`. 171 | // For custom options, it should be the fully-qualified name. For example, 172 | // `"google.api.http"`. 173 | string name = 1; 174 | // The option's value packed in an Any message. If the value is a primitive, 175 | // the corresponding wrapper type defined in google/protobuf/wrappers.proto 176 | // should be used. If the value is an enum, it should be stored as an int32 177 | // value using the google.protobuf.Int32Value type. 178 | Any value = 2; 179 | } 180 | 181 | // The syntax in which a protocol buffer element is defined. 182 | enum Syntax { 183 | // Syntax `proto2`. 184 | SYNTAX_PROTO2 = 0; 185 | // Syntax `proto3`. 186 | SYNTAX_PROTO3 = 1; 187 | } 188 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * For a detailed explanation regarding each configuration property and type check, visit: 3 | * https://jestjs.io/docs/configuration 4 | */ 5 | 6 | export default { 7 | // All imported modules in your tests should be mocked automatically 8 | // automock: false, 9 | 10 | // Stop running tests after `n` failures 11 | // bail: 0, 12 | 13 | // The directory where Jest should store its cached dependency information 14 | // cacheDirectory: "/private/var/folders/79/3htxplvx7fbddkzt95jtrsmm0000gp/T/jest_dy", 15 | 16 | // Automatically clear mock calls, instances and results before every test 17 | clearMocks: true, 18 | 19 | // Indicates whether the coverage information should be collected while executing the test 20 | collectCoverage: true, 21 | 22 | // An array of glob patterns indicating a set of files for which coverage information should be collected 23 | // collectCoverageFrom: undefined, 24 | 25 | // The directory where Jest should output its coverage files 26 | coverageDirectory: "coverage", 27 | 28 | // An array of regexp pattern strings used to skip coverage collection 29 | // coveragePathIgnorePatterns: [ 30 | // "/node_modules/" 31 | // ], 32 | 33 | // Indicates which provider should be used to instrument code for coverage 34 | // coverageProvider: "babel", 35 | 36 | // A list of reporter names that Jest uses when writing coverage reports 37 | // coverageReporters: [ 38 | // "json", 39 | // "text", 40 | // "lcov", 41 | // "clover" 42 | // ], 43 | 44 | // An object that configures minimum threshold enforcement for coverage results 45 | // coverageThreshold: undefined, 46 | 47 | // A path to a custom dependency extractor 48 | // dependencyExtractor: undefined, 49 | 50 | // Make calling deprecated APIs throw helpful error messages 51 | // errorOnDeprecated: false, 52 | 53 | // Force coverage collection from ignored files using an array of glob patterns 54 | // forceCoverageMatch: [], 55 | 56 | // A path to a module which exports an async function that is triggered once before all test suites 57 | // globalSetup: undefined, 58 | 59 | // A path to a module which exports an async function that is triggered once after all test suites 60 | // globalTeardown: undefined, 61 | 62 | // A set of global variables that need to be available in all test environments 63 | // globals: {}, 64 | 65 | // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. 66 | // maxWorkers: "50%", 67 | 68 | // An array of directory names to be searched recursively up from the requiring module's location 69 | // moduleDirectories: [ 70 | // "node_modules" 71 | // ], 72 | 73 | // An array of file extensions your modules use 74 | // moduleFileExtensions: [ 75 | // "js", 76 | // "jsx", 77 | // "ts", 78 | // "tsx", 79 | // "json", 80 | // "node" 81 | // ], 82 | 83 | // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module 84 | // moduleNameMapper: {}, 85 | 86 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader 87 | // modulePathIgnorePatterns: [], 88 | 89 | // Activates notifications for test results 90 | // notify: false, 91 | 92 | // An enum that specifies notification mode. Requires { notify: true } 93 | // notifyMode: "failure-change", 94 | 95 | // A preset that is used as a base for Jest's configuration 96 | // preset: undefined, 97 | 98 | // Run tests from one or more projects 99 | // projects: undefined, 100 | 101 | // Use this configuration option to add custom reporters to Jest 102 | // reporters: undefined, 103 | 104 | // Automatically reset mock state before every test 105 | // resetMocks: false, 106 | 107 | // Reset the module registry before running each individual test 108 | // resetModules: false, 109 | 110 | // A path to a custom resolver 111 | // resolver: undefined, 112 | 113 | // Automatically restore mock state and implementation before every test 114 | // restoreMocks: false, 115 | 116 | // The root directory that Jest should scan for tests and modules within 117 | // rootDir: undefined, 118 | 119 | // A list of paths to directories that Jest should use to search for files in 120 | // roots: [ 121 | // "" 122 | // ], 123 | 124 | // Allows you to use a custom runner instead of Jest's default test runner 125 | // runner: "jest-runner", 126 | 127 | // The paths to modules that run some code to configure or set up the testing environment before each test 128 | // setupFiles: [], 129 | 130 | // A list of paths to modules that run some code to configure or set up the testing framework before each test 131 | // setupFilesAfterEnv: [], 132 | 133 | // The number of seconds after which a test is considered as slow and reported as such in the results. 134 | // slowTestThreshold: 5, 135 | 136 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing 137 | // snapshotSerializers: [], 138 | 139 | // The test environment that will be used for testing 140 | // testEnvironment: "jest-environment-node", 141 | 142 | // Options that will be passed to the testEnvironment 143 | // testEnvironmentOptions: {}, 144 | 145 | // Adds a location field to test results 146 | // testLocationInResults: false, 147 | 148 | // The glob patterns Jest uses to detect test files 149 | testMatch: ["**/__tests__/**/?(*.)+(spec|test).[tj]s?(x)"], 150 | 151 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped 152 | // testPathIgnorePatterns: [ 153 | // "/node_modules/" 154 | // ], 155 | 156 | // The regexp pattern or array of patterns that Jest uses to detect test files 157 | // testRegex: [], 158 | 159 | // This option allows the use of a custom results processor 160 | // testResultsProcessor: undefined, 161 | 162 | // This option allows use of a custom test runner 163 | // testRunner: "jest-circus/runner", 164 | 165 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href 166 | // testURL: "http://localhost", 167 | 168 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" 169 | // timers: "real", 170 | 171 | // A map from regular expressions to paths to transformers 172 | // transform: undefined, 173 | 174 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation 175 | // transformIgnorePatterns: [ 176 | // "/node_modules/", 177 | // "\\.pnp\\.[^\\/]+$" 178 | // ], 179 | 180 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them 181 | // unmockedModulePathPatterns: undefined, 182 | 183 | // Indicates whether each individual test should be reported during the run 184 | // verbose: undefined, 185 | 186 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode 187 | // watchPathIgnorePatterns: [], 188 | 189 | // Whether to use watchman for file crawling 190 | // watchman: true, 191 | }; 192 | -------------------------------------------------------------------------------- /src/proto/index.ts: -------------------------------------------------------------------------------- 1 | import protoJs from "protobufjs"; 2 | import { join, resolve } from "path"; 3 | import { existsSync } from "fs-extra"; 4 | 5 | import { ApiFile, DependencyType } from "../apiInterface"; 6 | 7 | import { 8 | isEnum, 9 | isType, 10 | isService, 11 | typeGenInterface, 12 | typeGenInterfaceModule, 13 | enumGenEnum, 14 | serviceGenApiFunction, 15 | insertImport, 16 | } from "./core"; 17 | import { 18 | error, 19 | getRelativePathABDepth, 20 | log, 21 | recursionDirFindPath, 22 | } from "../utils"; 23 | import { Options } from "../index"; 24 | 25 | export function getProto2ApiData(options: Options) { 26 | log("Loading PB file ......"); 27 | const apiFileMap: { [fileName: string]: ApiFile } = {}; 28 | 29 | const { root, pbPaths } = parseProto( 30 | options.protoDir, 31 | options.files, 32 | options.depPath 33 | ); 34 | for (const p of pbPaths) { 35 | if (options?.ignore?.test(p.target)) { 36 | continue; 37 | } 38 | apiFileMap[p.path] = { 39 | protoPath: p.path, 40 | protoTargetPath: p.target, 41 | outputPath: join(options.output, p.target).replace(".proto", ".ts"), 42 | comment: "", 43 | imports: [], 44 | enums: [], 45 | interfaces: [], 46 | apiModules: [], 47 | apiPrefixPath: options.apiPrefixPath, 48 | }; 49 | } 50 | 51 | const visitRoot = (item: protoJs.Root) => { 52 | if (item.nested && !isType(item)) { 53 | // Do not filter deeply nested 54 | Object.keys(item.nested).forEach((key) => { 55 | visitRoot(item.nested[key] as protoJs.Root); 56 | }); 57 | } 58 | const apiFile = apiFileMap[item.filename]; 59 | if (item.filename && apiFile) { 60 | // Generate corresponding data for service 61 | if (isService(item)) { 62 | apiFile.apiModules.push(serviceGenApiFunction(item as any)); 63 | apiFile.apiModules.forEach((k) => 64 | k.functions.forEach((f) => { 65 | if ( 66 | f.req.resolvedPath && 67 | f.req.dependencyType === DependencyType.EXTERNAL 68 | ) { 69 | insertImport(apiFile.imports, f.req); 70 | } 71 | if ( 72 | f.res.resolvedPath && 73 | f.res.dependencyType === DependencyType.EXTERNAL 74 | ) { 75 | insertImport(apiFile.imports, f.res); 76 | } 77 | }) 78 | ); 79 | } 80 | // Generate corresponding data for enum 81 | if (isEnum(item)) { 82 | apiFile.enums.push(enumGenEnum(item as any)); 83 | } 84 | // Generate corresponding data for message 85 | if (isType(item)) { 86 | const _interface = typeGenInterface(item as any); 87 | if ((item as any).nested) { 88 | _interface.module = typeGenInterfaceModule(item as any); 89 | } 90 | apiFile.interfaces.push(_interface); 91 | // Generate corresponding data for imports 92 | _interface.members.forEach((k) => { 93 | if (k.propertyType.dependencyType === DependencyType.EXTERNAL) { 94 | insertImport(apiFile.imports, k.propertyType); 95 | } 96 | }); 97 | _interface.module?.interfaces?.forEach((i) => { 98 | i.members.forEach((k) => { 99 | if (k.propertyType.dependencyType === DependencyType.EXTERNAL) { 100 | insertImport(apiFile.imports, k.propertyType); 101 | } 102 | }); 103 | }); 104 | } 105 | } 106 | }; 107 | // outputFileSync("root.json", JSON.stringify(root.nested, null, 4)); 108 | visitRoot(root); 109 | log("Convert PB data to api data"); 110 | return pathPreprocessing( 111 | { 112 | apiFileMap, 113 | output: options.output, 114 | }, 115 | pbPaths 116 | ); 117 | } 118 | 119 | export type PathPreprocessingOption = { 120 | apiFileMap: { [fileName: string]: ApiFile }; 121 | output: string; 122 | }; 123 | /** 124 | * Do some preprocessing on the pb path 125 | * @param options 126 | * @returns 127 | */ 128 | export function pathPreprocessing( 129 | options: PathPreprocessingOption, 130 | pbPaths: Array<{ 131 | target: string; 132 | path: string; 133 | }> 134 | ): { 135 | [apiFilePath: string]: ApiFile; 136 | } { 137 | const { apiFileMap } = options; 138 | 139 | for (const fileName in apiFileMap) { 140 | const apiFile = apiFileMap[fileName]; 141 | 142 | apiFile.imports.forEach((k) => { 143 | if (k.resolvedPath) { 144 | const pathA = pbPaths 145 | .find((p) => p.path === k.resolvedPath) 146 | .target.replace(".proto", ""); 147 | const pathB = apiFile.protoTargetPath.slice( 148 | 0, 149 | apiFile.protoTargetPath.lastIndexOf("/") 150 | ); 151 | k.moduleSpecifier = getRelativePathABDepth(pathA, pathB); 152 | } 153 | }); 154 | 155 | apiFile.interfaces.forEach((inter) => { 156 | inter.members.forEach((mem) => { 157 | if (mem.propertyType.dependencyType === DependencyType.INLINE) { 158 | mem.propertyType.type = inter.name + "." + mem.propertyType.type; 159 | } 160 | }); 161 | }); 162 | } 163 | return apiFileMap; 164 | } 165 | 166 | export function parseProto( 167 | protoDir: string, 168 | protoFiles: string[], 169 | dependencyPath: string 170 | ) { 171 | const root = new protoJs.Root(); 172 | 173 | const pbPaths: Array<{ 174 | target: string; 175 | path: string; 176 | }> = []; 177 | const notFoundList = []; 178 | // Parse the imported PB to get the absolute path 179 | root.resolvePath = (origin, target) => { 180 | if (!protoDir && root.nested && root.files.length > 0) { 181 | const keys = Object.keys(root.nested); 182 | const firstPath = root.files[0]; 183 | const reg = firstPath.match(new RegExp(`/${keys[0]}/`)); 184 | reg && (protoDir = firstPath.slice(0, reg.index)); 185 | } 186 | let pathObj = { 187 | path: target, 188 | target: target.replace(protoDir, ""), 189 | }; 190 | if (!existsSync(pathObj.path)) { 191 | if (target.match(/^google/)) { 192 | pathObj = recursionDirFindPath( 193 | resolve(__dirname, "../../", "common"), 194 | target 195 | ); 196 | } else { 197 | const originDir = origin.slice(0, origin.lastIndexOf("/")); 198 | pathObj = recursionDirFindPath(protoDir, target); 199 | // This happens when the pb directory has no upper directory 200 | if (!protoDir) { 201 | protoDir = originDir; 202 | } 203 | } 204 | 205 | if (!pathObj.path && dependencyPath) { 206 | pathObj = recursionDirFindPath(dependencyPath, target); 207 | } 208 | 209 | if (!pathObj.path && !notFoundList.find((k) => k === target)) { 210 | notFoundList.push(target); 211 | } 212 | } 213 | 214 | pbPaths.push(pathObj); 215 | return pathObj.path; 216 | }; 217 | 218 | try { 219 | root 220 | .loadSync(protoFiles, { 221 | keepCase: true, 222 | alternateCommentMode: true, 223 | }) 224 | .resolveAll(); 225 | } catch (e) { 226 | console.error(e); 227 | if (notFoundList.length > 0) { 228 | error( 229 | "The following proto could not be found, if it is this project file, please try to specify --protoDir, if it is an external dependency file, please try to specify --depPath" 230 | ); 231 | console.log(notFoundList); 232 | console.log(); 233 | } 234 | } 235 | // remove absolute path 236 | pbPaths.forEach((obj) => { 237 | const target = obj.target.replace(protoDir, ""); 238 | obj.target = target.match(/^\//) ? target : "/" + target; 239 | }); 240 | return { 241 | root, 242 | pbPaths, 243 | }; 244 | } 245 | -------------------------------------------------------------------------------- /common/google/rpc/code.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.rpc; 18 | 19 | option go_package = "google.golang.org/genproto/googleapis/rpc/code;code"; 20 | option java_multiple_files = true; 21 | option java_outer_classname = "CodeProto"; 22 | option java_package = "com.google.rpc"; 23 | option objc_class_prefix = "RPC"; 24 | 25 | 26 | // The canonical error codes for Google APIs. 27 | // 28 | // 29 | // Sometimes multiple error codes may apply. Services should return 30 | // the most specific error code that applies. For example, prefer 31 | // `OUT_OF_RANGE` over `FAILED_PRECONDITION` if both codes apply. 32 | // Similarly prefer `NOT_FOUND` or `ALREADY_EXISTS` over `FAILED_PRECONDITION`. 33 | enum Code { 34 | // Not an error; returned on success 35 | // 36 | // HTTP Mapping: 200 OK 37 | OK = 0; 38 | 39 | // The operation was cancelled, typically by the caller. 40 | // 41 | // HTTP Mapping: 499 Client Closed Request 42 | CANCELLED = 1; 43 | 44 | // Unknown error. For example, this error may be returned when 45 | // a `Status` value received from another address space belongs to 46 | // an error space that is not known in this address space. Also 47 | // errors raised by APIs that do not return enough error information 48 | // may be converted to this error. 49 | // 50 | // HTTP Mapping: 500 Internal Server Error 51 | UNKNOWN = 2; 52 | 53 | // The client specified an invalid argument. Note that this differs 54 | // from `FAILED_PRECONDITION`. `INVALID_ARGUMENT` indicates arguments 55 | // that are problematic regardless of the state of the system 56 | // (e.g., a malformed file name). 57 | // 58 | // HTTP Mapping: 400 Bad Request 59 | INVALID_ARGUMENT = 3; 60 | 61 | // The deadline expired before the operation could complete. For operations 62 | // that change the state of the system, this error may be returned 63 | // even if the operation has completed successfully. For example, a 64 | // successful response from a server could have been delayed long 65 | // enough for the deadline to expire. 66 | // 67 | // HTTP Mapping: 504 Gateway Timeout 68 | DEADLINE_EXCEEDED = 4; 69 | 70 | // Some requested entity (e.g., file or directory) was not found. 71 | // 72 | // Note to server developers: if a request is denied for an entire class 73 | // of users, such as gradual feature rollout or undocumented whitelist, 74 | // `NOT_FOUND` may be used. If a request is denied for some users within 75 | // a class of users, such as user-based access control, `PERMISSION_DENIED` 76 | // must be used. 77 | // 78 | // HTTP Mapping: 404 Not Found 79 | NOT_FOUND = 5; 80 | 81 | // The entity that a client attempted to create (e.g., file or directory) 82 | // already exists. 83 | // 84 | // HTTP Mapping: 409 Conflict 85 | ALREADY_EXISTS = 6; 86 | 87 | // The caller does not have permission to execute the specified 88 | // operation. `PERMISSION_DENIED` must not be used for rejections 89 | // caused by exhausting some resource (use `RESOURCE_EXHAUSTED` 90 | // instead for those errors). `PERMISSION_DENIED` must not be 91 | // used if the caller can not be identified (use `UNAUTHENTICATED` 92 | // instead for those errors). This error code does not imply the 93 | // request is valid or the requested entity exists or satisfies 94 | // other pre-conditions. 95 | // 96 | // HTTP Mapping: 403 Forbidden 97 | PERMISSION_DENIED = 7; 98 | 99 | // The request does not have valid authentication credentials for the 100 | // operation. 101 | // 102 | // HTTP Mapping: 401 Unauthorized 103 | UNAUTHENTICATED = 16; 104 | 105 | // Some resource has been exhausted, perhaps a per-user quota, or 106 | // perhaps the entire file system is out of space. 107 | // 108 | // HTTP Mapping: 429 Too Many Requests 109 | RESOURCE_EXHAUSTED = 8; 110 | 111 | // The operation was rejected because the system is not in a state 112 | // required for the operation's execution. For example, the directory 113 | // to be deleted is non-empty, an rmdir operation is applied to 114 | // a non-directory, etc. 115 | // 116 | // Service implementors can use the following guidelines to decide 117 | // between `FAILED_PRECONDITION`, `ABORTED`, and `UNAVAILABLE`: 118 | // (a) Use `UNAVAILABLE` if the client can retry just the failing call. 119 | // (b) Use `ABORTED` if the client should retry at a higher level 120 | // (e.g., when a client-specified test-and-set fails, indicating the 121 | // client should restart a read-modify-write sequence). 122 | // (c) Use `FAILED_PRECONDITION` if the client should not retry until 123 | // the system state has been explicitly fixed. E.g., if an "rmdir" 124 | // fails because the directory is non-empty, `FAILED_PRECONDITION` 125 | // should be returned since the client should not retry unless 126 | // the files are deleted from the directory. 127 | // 128 | // HTTP Mapping: 400 Bad Request 129 | FAILED_PRECONDITION = 9; 130 | 131 | // The operation was aborted, typically due to a concurrency issue such as 132 | // a sequencer check failure or transaction abort. 133 | // 134 | // See the guidelines above for deciding between `FAILED_PRECONDITION`, 135 | // `ABORTED`, and `UNAVAILABLE`. 136 | // 137 | // HTTP Mapping: 409 Conflict 138 | ABORTED = 10; 139 | 140 | // The operation was attempted past the valid range. E.g., seeking or 141 | // reading past end-of-file. 142 | // 143 | // Unlike `INVALID_ARGUMENT`, this error indicates a problem that may 144 | // be fixed if the system state changes. For example, a 32-bit file 145 | // system will generate `INVALID_ARGUMENT` if asked to read at an 146 | // offset that is not in the range [0,2^32-1], but it will generate 147 | // `OUT_OF_RANGE` if asked to read from an offset past the current 148 | // file size. 149 | // 150 | // There is a fair bit of overlap between `FAILED_PRECONDITION` and 151 | // `OUT_OF_RANGE`. We recommend using `OUT_OF_RANGE` (the more specific 152 | // error) when it applies so that callers who are iterating through 153 | // a space can easily look for an `OUT_OF_RANGE` error to detect when 154 | // they are done. 155 | // 156 | // HTTP Mapping: 400 Bad Request 157 | OUT_OF_RANGE = 11; 158 | 159 | // The operation is not implemented or is not supported/enabled in this 160 | // service. 161 | // 162 | // HTTP Mapping: 501 Not Implemented 163 | UNIMPLEMENTED = 12; 164 | 165 | // Internal errors. This means that some invariants expected by the 166 | // underlying system have been broken. This error code is reserved 167 | // for serious errors. 168 | // 169 | // HTTP Mapping: 500 Internal Server Error 170 | INTERNAL = 13; 171 | 172 | // The service is currently unavailable. This is most likely a 173 | // transient condition, which can be corrected by retrying with 174 | // a backoff. 175 | // 176 | // See the guidelines above for deciding between `FAILED_PRECONDITION`, 177 | // `ABORTED`, and `UNAVAILABLE`. 178 | // 179 | // HTTP Mapping: 503 Service Unavailable 180 | UNAVAILABLE = 14; 181 | 182 | // Unrecoverable data loss or corruption. 183 | // 184 | // HTTP Mapping: 500 Internal Server Error 185 | DATA_LOSS = 15; 186 | } 187 | -------------------------------------------------------------------------------- /src/proto/core.ts: -------------------------------------------------------------------------------- 1 | import protoJs from "protobufjs"; 2 | import { isPrototype } from "../utils"; 3 | import { 4 | Interface, 5 | Enum, 6 | PropertySignature, 7 | ApiModule, 8 | InterfaceModule, 9 | DependencyType, 10 | PropertyType, 11 | Import, 12 | } from "../apiInterface"; 13 | 14 | export function isEnum(obj) { 15 | return isPrototype(obj, protoJs.Enum); 16 | } 17 | 18 | export function isType(obj) { 19 | return isPrototype(obj, protoJs.Type); 20 | } 21 | 22 | export function isNamespace(obj) { 23 | return isPrototype(obj, protoJs.Namespace); 24 | } 25 | 26 | export function isService(obj) { 27 | return isPrototype(obj, protoJs.Service); 28 | } 29 | 30 | /** 31 | * Because protobuf.js has special treatment for some modules of google, it needs to be converted 32 | * // protobuf.js/src/common.js 33 | * @param typeStr 34 | * @returns 35 | */ 36 | function getGoogleCommon(typeStr): string { 37 | if (typeStr === "google.protobuf.Empty") { 38 | return "{}"; 39 | } 40 | if (typeStr === "google.protobuf.Any") return `any`; 41 | return ""; 42 | } 43 | 44 | export function typeGenInterfaceModule(child: protoJs.Type): InterfaceModule { 45 | const result: InterfaceModule = { 46 | name: child.name, 47 | comment: `This the module of ${child.name}`, 48 | enums: [], 49 | interfaces: [], 50 | }; 51 | Object.keys(child.nested).forEach((key) => { 52 | const item = child.nested[key]; 53 | if (isType(item)) { 54 | result.interfaces.push(typeGenInterface(item as any)); 55 | } 56 | if (isEnum(item)) { 57 | result.enums.push(enumGenEnum(item as any)); 58 | } 59 | }); 60 | return result; 61 | } 62 | 63 | export function typeGenInterface(item: protoJs.Type): Interface { 64 | const result: Interface = { 65 | name: item.name, 66 | comment: item.comment, 67 | members: [], 68 | }; 69 | 70 | for (let i = 0; i < item.fieldsArray.length; i++) { 71 | const field = item.fieldsArray[i]; 72 | if (field.name.match(/\./)) { 73 | // Filter some strange data generated by protobuf.js itself 74 | continue; 75 | } 76 | // if (field.type.match(/xx/)) { 77 | // debugger; 78 | // } 79 | 80 | const member: PropertySignature = { 81 | name: field.name, 82 | propertyType: { 83 | type: field.type, 84 | dependencyTypeName: "", 85 | dependencyType: DependencyType.SYSTEM, 86 | resolvedPath: "", 87 | // @ts-ignorets 88 | keyType: field.keyType, 89 | map: field.map, 90 | }, 91 | comment: field.comment, 92 | 93 | repeated: field.repeated, 94 | optional: field.options ? field.options["proto3_optional"] : false, 95 | jsonName: field.options ? field.options["json_name"] : undefined, 96 | defaultValue: field.options ? field.options["default"] : undefined, 97 | }; 98 | // If the reference is to another type 99 | if (field.resolvedType) { 100 | // member.type = field.resolvedType.name 101 | // if (field.type.match(/google/)) { 102 | // debugger 103 | // } 104 | // member.type = field.type.match(/google/) ? field.resolvedType.name : '{}' 105 | // write reference path 106 | const type = getGoogleCommon(field.type) || field.resolvedType.name; 107 | const resolvedPath = 108 | field.filename === field.resolvedType.filename 109 | ? "" 110 | : field.resolvedType.filename; 111 | let dependencyType = DependencyType.SYSTEM; 112 | let dependencyTypeName = ""; 113 | if (field.filename === field.resolvedType.filename) { 114 | if (field.resolvedType.parent.name === item.name) { 115 | dependencyType = DependencyType.INLINE; 116 | } else { 117 | dependencyType = DependencyType.CURRENT; 118 | } 119 | } else if (field.resolvedType.filename) { 120 | dependencyType = DependencyType.EXTERNAL; 121 | dependencyTypeName = field.type; 122 | } 123 | member.propertyType = { 124 | ...member.propertyType, 125 | type, 126 | resolvedPath, 127 | dependencyType, 128 | dependencyTypeName, 129 | }; 130 | } 131 | result.members.push(member); 132 | } 133 | 134 | return result; 135 | } 136 | export function insertImport(arr: Import[], k: PropertyType) { 137 | const index = arr.findIndex((a) => k.resolvedPath === a.resolvedPath); 138 | if (index > -1) { 139 | // 如果import内已经有了该文件,但是type值还不存在的场合 140 | !arr[index].importClause.find((i) => i.type === k.type) && 141 | arr[index].importClause.push({ 142 | type: k.type, 143 | dependencyTypeName: k.dependencyTypeName, 144 | }); 145 | } else { 146 | // 如果是一个全新的 147 | arr.push({ 148 | importClause: [ 149 | { 150 | type: k.type, 151 | dependencyTypeName: k.dependencyTypeName, 152 | }, 153 | ], 154 | resolvedPath: k.resolvedPath, 155 | }); 156 | } 157 | } 158 | 159 | export function enumGenEnum(item: protoJs.Enum): Enum { 160 | const result: Enum = { 161 | name: item.name, 162 | comment: item.comment, 163 | members: Object.keys(item.values).map((k) => ({ 164 | name: k, 165 | // initializer: item.values[k], 166 | initializer: k, 167 | comment: item.comments[k], 168 | })), 169 | }; 170 | return result; 171 | } 172 | 173 | const httpType = { 174 | "(google.api.http).get": "get", 175 | "(google.api.http).post": "post", 176 | "(google.api.http).put": "put", 177 | "(google.api.http).patch": "patch", 178 | "(google.api.http).delete": "delete", 179 | }; 180 | const getHttpType = (options) => { 181 | const keys = Object.keys(options || {}); 182 | for (let k of keys) { 183 | if (httpType[k]) { 184 | return { 185 | method: httpType[k], 186 | url: options[k], 187 | }; 188 | } 189 | } 190 | 191 | return { 192 | method: "", 193 | url: "", 194 | }; 195 | }; 196 | 197 | function getApiFunctionPropertyType(k: protoJs.Method): { 198 | req: PropertyType; 199 | res: PropertyType; 200 | } { 201 | const { resolvedRequestType: reqT, resolvedResponseType: resT } = k; 202 | const reqType = getGoogleCommon(k.requestType); 203 | const resType = getGoogleCommon(k.responseType); 204 | 205 | return { 206 | req: { 207 | type: reqType || (reqT ? reqT.name : k.requestType), 208 | dependencyType: 209 | k.filename === reqT.filename 210 | ? DependencyType.CURRENT 211 | : DependencyType.EXTERNAL, 212 | dependencyTypeName: k.requestType, 213 | resolvedPath: reqT ? reqT.filename : "", 214 | }, 215 | res: { 216 | type: resType || (resT ? resT.name : k.responseType), 217 | dependencyType: 218 | k.filename === resT.filename 219 | ? DependencyType.CURRENT 220 | : DependencyType.EXTERNAL, 221 | dependencyTypeName: k.responseType, 222 | resolvedPath: resT ? resT.filename : "", 223 | }, 224 | }; 225 | } 226 | 227 | export function serviceGenApiFunction(item: protoJs.Service): ApiModule { 228 | const result: ApiModule = { 229 | comment: item.comment, 230 | name: item.name, 231 | functions: item.methodsArray.map((k) => { 232 | const httpType = getHttpType(k.options); 233 | 234 | let comment = k.comment || ""; 235 | const redirectReg = comment.match(/\@redirect\s*(\S+)/); 236 | let redirectUrl = ""; 237 | if (redirectReg && redirectReg.length) { 238 | redirectUrl = redirectReg[1]; 239 | comment = comment.replace( 240 | /\@redirect\s*(\S+)/, 241 | "@originUrl: " + httpType.url 242 | ); 243 | } 244 | const methodReg = comment.match(/\@method\s*(\S+)/); 245 | let commentMethod = "post"; 246 | if (methodReg && methodReg.length) { 247 | commentMethod = methodReg[1]; 248 | } 249 | const { req, res } = getApiFunctionPropertyType(k); 250 | return { 251 | name: k.name, 252 | comment, 253 | req, 254 | // reqResolvedPath: resFn === k.filename ? "" : resFn, 255 | url: httpType.url, 256 | redirectUrl, 257 | res, 258 | // resResolvedPath: repFn === k.filename ? "" : repFn, 259 | method: (httpType.method || commentMethod).toLowerCase(), 260 | }; 261 | }), 262 | }; 263 | return result; 264 | } 265 | -------------------------------------------------------------------------------- /common/google/rpc/error_details.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.rpc; 18 | 19 | import "google/protobuf/duration.proto"; 20 | 21 | option go_package = "google.golang.org/genproto/googleapis/rpc/errdetails;errdetails"; 22 | option java_multiple_files = true; 23 | option java_outer_classname = "ErrorDetailsProto"; 24 | option java_package = "com.google.rpc"; 25 | option objc_class_prefix = "RPC"; 26 | 27 | 28 | // Describes when the clients can retry a failed request. Clients could ignore 29 | // the recommendation here or retry when this information is missing from error 30 | // responses. 31 | // 32 | // It's always recommended that clients should use exponential backoff when 33 | // retrying. 34 | // 35 | // Clients should wait until `retry_delay` amount of time has passed since 36 | // receiving the error response before retrying. If retrying requests also 37 | // fail, clients should use an exponential backoff scheme to gradually increase 38 | // the delay between retries based on `retry_delay`, until either a maximum 39 | // number of retires have been reached or a maximum retry delay cap has been 40 | // reached. 41 | message RetryInfo { 42 | // Clients should wait at least this long between retrying the same request. 43 | google.protobuf.Duration retry_delay = 1; 44 | } 45 | 46 | // Describes additional debugging info. 47 | message DebugInfo { 48 | // The stack trace entries indicating where the error occurred. 49 | repeated string stack_entries = 1; 50 | 51 | // Additional debugging information provided by the server. 52 | string detail = 2; 53 | } 54 | 55 | // Describes how a quota check failed. 56 | // 57 | // For example if a daily limit was exceeded for the calling project, 58 | // a service could respond with a QuotaFailure detail containing the project 59 | // id and the description of the quota limit that was exceeded. If the 60 | // calling project hasn't enabled the service in the developer console, then 61 | // a service could respond with the project id and set `service_disabled` 62 | // to true. 63 | // 64 | // Also see RetryDetail and Help types for other details about handling a 65 | // quota failure. 66 | message QuotaFailure { 67 | // A message type used to describe a single quota violation. For example, a 68 | // daily quota or a custom quota that was exceeded. 69 | message Violation { 70 | // The subject on which the quota check failed. 71 | // For example, "clientip:" or "project:". 73 | string subject = 1; 74 | 75 | // A description of how the quota check failed. Clients can use this 76 | // description to find more about the quota configuration in the service's 77 | // public documentation, or find the relevant quota limit to adjust through 78 | // developer console. 79 | // 80 | // For example: "Service disabled" or "Daily Limit for read operations 81 | // exceeded". 82 | string description = 2; 83 | } 84 | 85 | // Describes all quota violations. 86 | repeated Violation violations = 1; 87 | } 88 | 89 | // Describes what preconditions have failed. 90 | // 91 | // For example, if an RPC failed because it required the Terms of Service to be 92 | // acknowledged, it could list the terms of service violation in the 93 | // PreconditionFailure message. 94 | message PreconditionFailure { 95 | // A message type used to describe a single precondition failure. 96 | message Violation { 97 | // The type of PreconditionFailure. We recommend using a service-specific 98 | // enum type to define the supported precondition violation types. For 99 | // example, "TOS" for "Terms of Service violation". 100 | string type = 1; 101 | 102 | // The subject, relative to the type, that failed. 103 | // For example, "google.com/cloud" relative to the "TOS" type would 104 | // indicate which terms of service is being referenced. 105 | string subject = 2; 106 | 107 | // A description of how the precondition failed. Developers can use this 108 | // description to understand how to fix the failure. 109 | // 110 | // For example: "Terms of service not accepted". 111 | string description = 3; 112 | } 113 | 114 | // Describes all precondition violations. 115 | repeated Violation violations = 1; 116 | } 117 | 118 | // Describes violations in a client request. This error type focuses on the 119 | // syntactic aspects of the request. 120 | message BadRequest { 121 | // A message type used to describe a single bad request field. 122 | message FieldViolation { 123 | // A path leading to a field in the request body. The value will be a 124 | // sequence of dot-separated identifiers that identify a protocol buffer 125 | // field. E.g., "field_violations.field" would identify this field. 126 | string field = 1; 127 | 128 | // A description of why the request element is bad. 129 | string description = 2; 130 | } 131 | 132 | // Describes all violations in a client request. 133 | repeated FieldViolation field_violations = 1; 134 | } 135 | 136 | // Contains metadata about the request that clients can attach when filing a bug 137 | // or providing other forms of feedback. 138 | message RequestInfo { 139 | // An opaque string that should only be interpreted by the service generating 140 | // it. For example, it can be used to identify requests in the service's logs. 141 | string request_id = 1; 142 | 143 | // Any data that was used to serve this request. For example, an encrypted 144 | // stack trace that can be sent back to the service provider for debugging. 145 | string serving_data = 2; 146 | } 147 | 148 | // Describes the resource that is being accessed. 149 | message ResourceInfo { 150 | // A name for the type of resource being accessed, e.g. "sql table", 151 | // "cloud storage bucket", "file", "Google calendar"; or the type URL 152 | // of the resource: e.g. "type.googleapis.com/google.pubsub.v1.Topic". 153 | string resource_type = 1; 154 | 155 | // The name of the resource being accessed. For example, a shared calendar 156 | // name: "example.com_4fghdhgsrgh@group.calendar.google.com", if the current 157 | // error is [google.rpc.Code.PERMISSION_DENIED][google.rpc.Code.PERMISSION_DENIED]. 158 | string resource_name = 2; 159 | 160 | // The owner of the resource (optional). 161 | // For example, "user:" or "project:". 163 | string owner = 3; 164 | 165 | // Describes what error is encountered when accessing this resource. 166 | // For example, updating a cloud project may require the `writer` permission 167 | // on the developer console project. 168 | string description = 4; 169 | } 170 | 171 | // Provides links to documentation or for performing an out of band action. 172 | // 173 | // For example, if a quota check failed with an error indicating the calling 174 | // project hasn't enabled the accessed service, this can contain a URL pointing 175 | // directly to the right place in the developer console to flip the bit. 176 | message Help { 177 | // Describes a URL link. 178 | message Link { 179 | // Describes what the link offers. 180 | string description = 1; 181 | 182 | // The URL of the link. 183 | string url = 2; 184 | } 185 | 186 | // URL(s) pointing to additional information on handling the current error. 187 | repeated Link links = 1; 188 | } 189 | 190 | // Provides a localized error message that is safe to return to the user 191 | // which can be attached to an RPC error. 192 | message LocalizedMessage { 193 | // The locale used following the specification defined at 194 | // http://www.rfc-editor.org/rfc/bcp/bcp47.txt. 195 | // Examples are: "en-US", "fr-CH", "es-MX" 196 | string locale = 1; 197 | 198 | // The localized error message in the above locale. 199 | string message = 2; 200 | } 201 | -------------------------------------------------------------------------------- /common/google/protobuf/api.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | import "google/protobuf/source_context.proto"; 36 | import "google/protobuf/type.proto"; 37 | 38 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 39 | option java_package = "com.google.protobuf"; 40 | option java_outer_classname = "ApiProto"; 41 | option java_multiple_files = true; 42 | option objc_class_prefix = "GPB"; 43 | option go_package = "google.golang.org/genproto/protobuf/api;api"; 44 | 45 | // Api is a light-weight descriptor for an API Interface. 46 | // 47 | // Interfaces are also described as "protocol buffer services" in some contexts, 48 | // such as by the "service" keyword in a .proto file, but they are different 49 | // from API Services, which represent a concrete implementation of an interface 50 | // as opposed to simply a description of methods and bindings. They are also 51 | // sometimes simply referred to as "APIs" in other contexts, such as the name of 52 | // this message itself. See https://cloud.google.com/apis/design/glossary for 53 | // detailed terminology. 54 | message Api { 55 | 56 | // The fully qualified name of this interface, including package name 57 | // followed by the interface's simple name. 58 | string name = 1; 59 | 60 | // The methods of this interface, in unspecified order. 61 | repeated Method methods = 2; 62 | 63 | // Any metadata attached to the interface. 64 | repeated Option options = 3; 65 | 66 | // A version string for this interface. If specified, must have the form 67 | // `major-version.minor-version`, as in `1.10`. If the minor version is 68 | // omitted, it defaults to zero. If the entire version field is empty, the 69 | // major version is derived from the package name, as outlined below. If the 70 | // field is not empty, the version in the package name will be verified to be 71 | // consistent with what is provided here. 72 | // 73 | // The versioning schema uses [semantic 74 | // versioning](http://semver.org) where the major version number 75 | // indicates a breaking change and the minor version an additive, 76 | // non-breaking change. Both version numbers are signals to users 77 | // what to expect from different versions, and should be carefully 78 | // chosen based on the product plan. 79 | // 80 | // The major version is also reflected in the package name of the 81 | // interface, which must end in `v`, as in 82 | // `google.feature.v1`. For major versions 0 and 1, the suffix can 83 | // be omitted. Zero major versions must only be used for 84 | // experimental, non-GA interfaces. 85 | // 86 | // 87 | string version = 4; 88 | 89 | // Source context for the protocol buffer service represented by this 90 | // message. 91 | SourceContext source_context = 5; 92 | 93 | // Included interfaces. See [Mixin][]. 94 | repeated Mixin mixins = 6; 95 | 96 | // The source syntax of the service. 97 | Syntax syntax = 7; 98 | } 99 | 100 | // Method represents a method of an API interface. 101 | message Method { 102 | 103 | // The simple name of this method. 104 | string name = 1; 105 | 106 | // A URL of the input message type. 107 | string request_type_url = 2; 108 | 109 | // If true, the request is streamed. 110 | bool request_streaming = 3; 111 | 112 | // The URL of the output message type. 113 | string response_type_url = 4; 114 | 115 | // If true, the response is streamed. 116 | bool response_streaming = 5; 117 | 118 | // Any metadata attached to the method. 119 | repeated Option options = 6; 120 | 121 | // The source syntax of this method. 122 | Syntax syntax = 7; 123 | } 124 | 125 | // Declares an API Interface to be included in this interface. The including 126 | // interface must redeclare all the methods from the included interface, but 127 | // documentation and options are inherited as follows: 128 | // 129 | // - If after comment and whitespace stripping, the documentation 130 | // string of the redeclared method is empty, it will be inherited 131 | // from the original method. 132 | // 133 | // - Each annotation belonging to the service config (http, 134 | // visibility) which is not set in the redeclared method will be 135 | // inherited. 136 | // 137 | // - If an http annotation is inherited, the path pattern will be 138 | // modified as follows. Any version prefix will be replaced by the 139 | // version of the including interface plus the [root][] path if 140 | // specified. 141 | // 142 | // Example of a simple mixin: 143 | // 144 | // package google.acl.v1; 145 | // service AccessControl { 146 | // // Get the underlying ACL object. 147 | // rpc GetAcl(GetAclRequest) returns (Acl) { 148 | // option (google.api.http).get = "/v1/{resource=**}:getAcl"; 149 | // } 150 | // } 151 | // 152 | // package google.storage.v2; 153 | // service Storage { 154 | // rpc GetAcl(GetAclRequest) returns (Acl); 155 | // 156 | // // Get a data record. 157 | // rpc GetData(GetDataRequest) returns (Data) { 158 | // option (google.api.http).get = "/v2/{resource=**}"; 159 | // } 160 | // } 161 | // 162 | // Example of a mixin configuration: 163 | // 164 | // apis: 165 | // - name: google.storage.v2.Storage 166 | // mixins: 167 | // - name: google.acl.v1.AccessControl 168 | // 169 | // The mixin construct implies that all methods in `AccessControl` are 170 | // also declared with same name and request/response types in 171 | // `Storage`. A documentation generator or annotation processor will 172 | // see the effective `Storage.GetAcl` method after inherting 173 | // documentation and annotations as follows: 174 | // 175 | // service Storage { 176 | // // Get the underlying ACL object. 177 | // rpc GetAcl(GetAclRequest) returns (Acl) { 178 | // option (google.api.http).get = "/v2/{resource=**}:getAcl"; 179 | // } 180 | // ... 181 | // } 182 | // 183 | // Note how the version in the path pattern changed from `v1` to `v2`. 184 | // 185 | // If the `root` field in the mixin is specified, it should be a 186 | // relative path under which inherited HTTP paths are placed. Example: 187 | // 188 | // apis: 189 | // - name: google.storage.v2.Storage 190 | // mixins: 191 | // - name: google.acl.v1.AccessControl 192 | // root: acls 193 | // 194 | // This implies the following inherited HTTP annotation: 195 | // 196 | // service Storage { 197 | // // Get the underlying ACL object. 198 | // rpc GetAcl(GetAclRequest) returns (Acl) { 199 | // option (google.api.http).get = "/v2/acls/{resource=**}:getAcl"; 200 | // } 201 | // ... 202 | // } 203 | message Mixin { 204 | // The fully qualified name of the interface which is included. 205 | string name = 1; 206 | 207 | // If non-empty specifies a path under which inherited HTTP paths 208 | // are rooted. 209 | string root = 2; 210 | } 211 | -------------------------------------------------------------------------------- /common/google/protobuf/field_mask.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option java_package = "com.google.protobuf"; 37 | option java_outer_classname = "FieldMaskProto"; 38 | option java_multiple_files = true; 39 | option objc_class_prefix = "GPB"; 40 | option go_package = "google.golang.org/genproto/protobuf/field_mask;field_mask"; 41 | option cc_enable_arenas = true; 42 | 43 | // `FieldMask` represents a set of symbolic field paths, for example: 44 | // 45 | // paths: "f.a" 46 | // paths: "f.b.d" 47 | // 48 | // Here `f` represents a field in some root message, `a` and `b` 49 | // fields in the message found in `f`, and `d` a field found in the 50 | // message in `f.b`. 51 | // 52 | // Field masks are used to specify a subset of fields that should be 53 | // returned by a get operation or modified by an update operation. 54 | // Field masks also have a custom JSON encoding (see below). 55 | // 56 | // # Field Masks in Projections 57 | // 58 | // When used in the context of a projection, a response message or 59 | // sub-message is filtered by the API to only contain those fields as 60 | // specified in the mask. For example, if the mask in the previous 61 | // example is applied to a response message as follows: 62 | // 63 | // f { 64 | // a : 22 65 | // b { 66 | // d : 1 67 | // x : 2 68 | // } 69 | // y : 13 70 | // } 71 | // z: 8 72 | // 73 | // The result will not contain specific values for fields x,y and z 74 | // (their value will be set to the default, and omitted in proto text 75 | // output): 76 | // 77 | // 78 | // f { 79 | // a : 22 80 | // b { 81 | // d : 1 82 | // } 83 | // } 84 | // 85 | // A repeated field is not allowed except at the last position of a 86 | // paths string. 87 | // 88 | // If a FieldMask object is not present in a get operation, the 89 | // operation applies to all fields (as if a FieldMask of all fields 90 | // had been specified). 91 | // 92 | // Note that a field mask does not necessarily apply to the 93 | // top-level response message. In case of a REST get operation, the 94 | // field mask applies directly to the response, but in case of a REST 95 | // list operation, the mask instead applies to each individual message 96 | // in the returned resource list. In case of a REST custom method, 97 | // other definitions may be used. Where the mask applies will be 98 | // clearly documented together with its declaration in the API. In 99 | // any case, the effect on the returned resource/resources is required 100 | // behavior for APIs. 101 | // 102 | // # Field Masks in Update Operations 103 | // 104 | // A field mask in update operations specifies which fields of the 105 | // targeted resource are going to be updated. The API is required 106 | // to only change the values of the fields as specified in the mask 107 | // and leave the others untouched. If a resource is passed in to 108 | // describe the updated values, the API ignores the values of all 109 | // fields not covered by the mask. 110 | // 111 | // If a repeated field is specified for an update operation, new values will 112 | // be appended to the existing repeated field in the target resource. Note that 113 | // a repeated field is only allowed in the last position of a `paths` string. 114 | // 115 | // If a sub-message is specified in the last position of the field mask for an 116 | // update operation, then new value will be merged into the existing sub-message 117 | // in the target resource. 118 | // 119 | // For example, given the target message: 120 | // 121 | // f { 122 | // b { 123 | // d: 1 124 | // x: 2 125 | // } 126 | // c: [1] 127 | // } 128 | // 129 | // And an update message: 130 | // 131 | // f { 132 | // b { 133 | // d: 10 134 | // } 135 | // c: [2] 136 | // } 137 | // 138 | // then if the field mask is: 139 | // 140 | // paths: ["f.b", "f.c"] 141 | // 142 | // then the result will be: 143 | // 144 | // f { 145 | // b { 146 | // d: 10 147 | // x: 2 148 | // } 149 | // c: [1, 2] 150 | // } 151 | // 152 | // An implementation may provide options to override this default behavior for 153 | // repeated and message fields. 154 | // 155 | // In order to reset a field's value to the default, the field must 156 | // be in the mask and set to the default value in the provided resource. 157 | // Hence, in order to reset all fields of a resource, provide a default 158 | // instance of the resource and set all fields in the mask, or do 159 | // not provide a mask as described below. 160 | // 161 | // If a field mask is not present on update, the operation applies to 162 | // all fields (as if a field mask of all fields has been specified). 163 | // Note that in the presence of schema evolution, this may mean that 164 | // fields the client does not know and has therefore not filled into 165 | // the request will be reset to their default. If this is unwanted 166 | // behavior, a specific service may require a client to always specify 167 | // a field mask, producing an error if not. 168 | // 169 | // As with get operations, the location of the resource which 170 | // describes the updated values in the request message depends on the 171 | // operation kind. In any case, the effect of the field mask is 172 | // required to be honored by the API. 173 | // 174 | // ## Considerations for HTTP REST 175 | // 176 | // The HTTP kind of an update operation which uses a field mask must 177 | // be set to PATCH instead of PUT in order to satisfy HTTP semantics 178 | // (PUT must only be used for full updates). 179 | // 180 | // # JSON Encoding of Field Masks 181 | // 182 | // In JSON, a field mask is encoded as a single string where paths are 183 | // separated by a comma. Fields name in each path are converted 184 | // to/from lower-camel naming conventions. 185 | // 186 | // As an example, consider the following message declarations: 187 | // 188 | // message Profile { 189 | // User user = 1; 190 | // Photo photo = 2; 191 | // } 192 | // message User { 193 | // string display_name = 1; 194 | // string address = 2; 195 | // } 196 | // 197 | // In proto a field mask for `Profile` may look as such: 198 | // 199 | // mask { 200 | // paths: "user.display_name" 201 | // paths: "photo" 202 | // } 203 | // 204 | // In JSON, the same mask is represented as below: 205 | // 206 | // { 207 | // mask: "user.displayName,photo" 208 | // } 209 | // 210 | // # Field Masks and Oneof Fields 211 | // 212 | // Field masks treat fields in oneofs just as regular fields. Consider the 213 | // following message: 214 | // 215 | // message SampleMessage { 216 | // oneof test_oneof { 217 | // string name = 4; 218 | // SubMessage sub_message = 9; 219 | // } 220 | // } 221 | // 222 | // The field mask can be: 223 | // 224 | // mask { 225 | // paths: "name" 226 | // } 227 | // 228 | // Or: 229 | // 230 | // mask { 231 | // paths: "sub_message" 232 | // } 233 | // 234 | // Note that oneof type names ("test_oneof" in this case) cannot be used in 235 | // paths. 236 | // 237 | // ## Field Mask Verification 238 | // 239 | // The implementation of any API method which has a FieldMask type field in the 240 | // request should verify the included field paths, and return an 241 | // `INVALID_ARGUMENT` error if any path is duplicated or unmappable. 242 | message FieldMask { 243 | // The set of field mask paths. 244 | repeated string paths = 1; 245 | } 246 | -------------------------------------------------------------------------------- /src/genTsApi.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ApiFile, 3 | Import, 4 | Enum, 5 | EnumMember, 6 | Interface, 7 | PropertySignature, 8 | InterfaceModule, 9 | ApiModule, 10 | ApiFunction, 11 | DependencyType, 12 | PropertyType, 13 | } from "./apiInterface"; 14 | 15 | import { format, toHump } from "./utils"; 16 | 17 | export function renderComment( 18 | comment: string, 19 | isNewline: boolean = true 20 | ): string { 21 | const str = comment 22 | ? comment 23 | .split("\n") 24 | .map((k) => `// ${k}`) 25 | .join("\n") 26 | : ""; 27 | if (str) return isNewline ? str + "\n" : str; 28 | else return str; 29 | } 30 | 31 | function renderTypeName( 32 | info: { type: string; aliasName: string }, 33 | messageMap: { [key: string]: 1 }, 34 | isImport: boolean = false 35 | ) { 36 | let name = info.type; 37 | if (messageMap[info.type]) { 38 | if (isImport) { 39 | name = name + " as " + toHump(info.aliasName, true); 40 | } else { 41 | name = toHump(info.aliasName, true); 42 | } 43 | } 44 | return name; 45 | } 46 | /** 47 | * list = [{ 48 | * importClause: ['A', 'B', 'C'], 49 | * moduleSpecifier: "./moduleA" 50 | * }] 51 | * => 52 | * import { A , B, C } from "./moduleA" 53 | * @param list 54 | * @returns 55 | */ 56 | export function renderImport(list: Import[], messageMap: { [key: string]: 1 }) { 57 | return list 58 | .map((k) => { 59 | return `import { ${k.importClause 60 | .map((i) => 61 | renderTypeName( 62 | { type: i.type, aliasName: i.dependencyTypeName }, 63 | messageMap, 64 | true 65 | ) 66 | ) 67 | .join(",")} } from '${k.moduleSpecifier}'`; 68 | }) 69 | .join("\n"); 70 | } 71 | 72 | /** 73 | * list = [{ 74 | * name: Status, 75 | * members: [{ 76 | * name: 'START', 77 | * initializer: 'start' 78 | * },{ 79 | * name: 'END', 80 | initializer: 'end' 81 | * }] 82 | * }] 83 | * => 84 | * export enum Status{ 85 | * START = 'start', 86 | * END = 'end' 87 | * } 88 | * @param list 89 | * @returns 90 | */ 91 | export function renderEnum(list: Enum[]) { 92 | const renderMembers = (member: EnumMember) => { 93 | if (member.initializer && isNaN(member.initializer as number)) { 94 | return `${renderComment(member.comment)}${member.name} = '${ 95 | member.initializer 96 | }'`; 97 | } else { 98 | return `${renderComment(member.comment)}${member.name}`; 99 | } 100 | }; 101 | 102 | return list 103 | .map( 104 | (k) => `${renderComment(k.comment)}export enum ${k.name} { 105 | ${k.members.map((m) => renderMembers(m)).join(",\n")} 106 | }` 107 | ) 108 | .join("\n"); 109 | } 110 | export function renderInterfaceModule( 111 | list: InterfaceModule[], 112 | messageMap: { [key: string]: 1 } 113 | ) { 114 | return list 115 | .map( 116 | (k) => `${renderComment(k.comment)}export namespace ${k.name}{ 117 | ${renderEnum(k.enums)} 118 | 119 | ${renderInterface(k.interfaces, messageMap)} 120 | }` 121 | ) 122 | .join("\n"); 123 | } 124 | 125 | function getProtoType(type: string): string { 126 | switch (type) { 127 | case "bool": 128 | return "boolean"; 129 | case "int32": 130 | case "fixed32": 131 | case "uint32": 132 | case "float": 133 | case "double": 134 | return "number"; 135 | case "int64": 136 | case "uint64": 137 | case "fixed64": 138 | case "bytes": 139 | return "string"; 140 | default: 141 | return type; 142 | } 143 | } 144 | 145 | function getType(k: PropertyType, messageMap: { [key: string]: 1 }) { 146 | let type = getProtoType(k.type); 147 | if (k.dependencyType === DependencyType.EXTERNAL) { 148 | type = renderTypeName( 149 | { 150 | type: k.type, 151 | aliasName: k.dependencyTypeName, 152 | }, 153 | messageMap 154 | ); 155 | } 156 | if (k.map) { 157 | // return `Map<${getProtoType(k.keyType)},${k.type}>`; 158 | return `{ [key: ${getProtoType(k.keyType)}]: ${type} }`; 159 | } 160 | return type; 161 | } 162 | 163 | /** 164 | * 生成ts的原始类型,方便后续做扩展 165 | * @param k 166 | * @returns 167 | */ 168 | const getComponentByPropertySignature = ( 169 | k: PropertySignature, 170 | tsType: string 171 | ) => { 172 | let comment = k.comment || ""; 173 | if (k.defaultValue) { 174 | comment += "@default=" + k.defaultValue; 175 | } 176 | if (tsType !== k.propertyType.type) { 177 | comment += " @" + k.propertyType.type; 178 | } 179 | return comment; 180 | }; 181 | export const renderPropertySignature = ( 182 | ps: PropertySignature[], 183 | messageMap: { [key: string]: 1 } 184 | ) => { 185 | return ps 186 | .map((k) => { 187 | const name = k.jsonName ? k.jsonName : k.name; 188 | const type = getType(k.propertyType, messageMap); 189 | let optional = k.optional; 190 | if (k?.comment?.match(/optional/)) { 191 | optional = true; 192 | } 193 | return `${renderComment( 194 | getComponentByPropertySignature(k, type) 195 | )}${name}${optional ? "?" : ""} : ${k.repeated ? type + "[]" : type};`; 196 | }) 197 | .join("\n"); 198 | }; 199 | 200 | export function renderInterface( 201 | list: Interface[], 202 | messageMap: { [key: string]: 1 } 203 | ) { 204 | return list 205 | .map((k) => { 206 | let str = ""; 207 | if (k.module) { 208 | str = renderInterfaceModule([k.module], messageMap); 209 | } 210 | str += `${renderComment(k.comment)}export interface ${k.name}{ 211 | ${renderPropertySignature(k.members, messageMap)} 212 | }`; 213 | return str; 214 | }) 215 | .join("\n\n"); 216 | } 217 | 218 | const configStr = "config?"; 219 | /** 220 | * list = [{ 221 | * name: 'getStatus', 222 | * apiName: 'webapi', 223 | * req: 'GetStatusRequest', 224 | * res: 'GetResponse', 225 | * url: '/api/xxx', 226 | * method: 'get', 227 | * }] 228 | * 229 | * => 230 | * export function getStatus(req: GetStatusRequest){ 231 | * return webapi.get('/api/xxx', req) 232 | * } 233 | * @param list 234 | * @returns 235 | */ 236 | export function renderFunction( 237 | list: ApiFunction[], 238 | apiName: string, 239 | apiPrefixPath: string, 240 | messageMap: { [key: string]: 1 } 241 | ): string { 242 | const renderReturn = (k: ApiFunction) => { 243 | const _url = k.redirectUrl ? k.redirectUrl : k.url; 244 | const url = apiPrefixPath ? apiPrefixPath + _url : _url; 245 | if (k.req.type) { 246 | return ` return ${apiName}.${k.method}<${getType( 247 | k.res, 248 | messageMap 249 | )}>('${url}', req, config)`; 250 | } else { 251 | return ` return ${apiName}.${k.method}<${getType( 252 | k.res, 253 | messageMap 254 | )}>('${url}', {}, config)`; 255 | } 256 | }; 257 | 258 | return list 259 | .map((k) => { 260 | const reqStr = k.req.type 261 | ? `req: Partial<${getType(k.req, messageMap)}>, ${configStr}` 262 | : configStr; 263 | return `${renderComment(k.comment)}export function ${k.name}(${reqStr}){ 264 | ${renderReturn(k)} 265 | }`; 266 | }) 267 | .join("\n\n"); 268 | } 269 | 270 | export function renderApiModule( 271 | list: ApiModule[], 272 | apiName: string, 273 | apiPrefixPath: string, 274 | messageMap: { [key: string]: 1 } 275 | ): string { 276 | // return list 277 | // .map( 278 | // (k) => `${renderComment(k.comment)}export namespace ${k.name}{ 279 | // ${renderFunction(k.functions, apiName)} 280 | // }` 281 | // ) 282 | // .join("\n\n"); 283 | 284 | return list 285 | .map( 286 | (k) => ` 287 | ${renderComment(k.comment + "\n" + k.name)} 288 | ${renderFunction(k.functions, apiName, apiPrefixPath, messageMap)} 289 | ` 290 | ) 291 | .join("\n\n"); 292 | } 293 | 294 | export function genApiFileCode( 295 | apiInfo: ApiFile, 296 | apiName: string, 297 | apiPrefixPath: string, 298 | messageMap: { [key: string]: 1 } 299 | ): string { 300 | return `// This is code generated automatically by the proto2api, please do not modify 301 | ${renderComment(apiInfo.comment)} 302 | ${renderImport(apiInfo.imports, messageMap)} 303 | ${renderEnum(apiInfo.enums)} 304 | ${renderInterface(apiInfo.interfaces, messageMap)} 305 | ${renderApiModule(apiInfo.apiModules, apiName, apiPrefixPath, messageMap)} 306 | `; 307 | } 308 | 309 | export type GenCodeOptions = { 310 | apiFileMap: { [fileName: string]: ApiFile }; 311 | apiName: string; 312 | apiPath: string; 313 | apiPrefixPath: string; 314 | eslintDisable?: boolean; 315 | }; 316 | export function genCode(options: GenCodeOptions): { 317 | [apiFilePath: string]: [code: string]; 318 | } { 319 | const result = {}; 320 | const { 321 | apiFileMap, 322 | apiName, 323 | apiPath, 324 | apiPrefixPath, 325 | eslintDisable = true, 326 | } = options; 327 | 328 | for (const fileName in apiFileMap) { 329 | const apiFile = apiFileMap[fileName]; 330 | if (apiFile.apiModules.length > 0) { 331 | // If this is a proto with api calls, need to import the configured webapi 332 | apiFile.imports.unshift({ 333 | importClause: [ 334 | { 335 | type: apiName, 336 | }, 337 | ], 338 | moduleSpecifier: apiPath, 339 | }); 340 | } 341 | 342 | const messageMap = {}; 343 | apiFile.interfaces.forEach((k) => { 344 | messageMap[k.name] = 1; 345 | k.module && 346 | k.module.interfaces.forEach((i) => { 347 | messageMap[k.name + "." + i.name] = 1; 348 | }); 349 | k.module && 350 | k.module.enums.forEach((i) => { 351 | messageMap[k.name + "." + i.name] = 1; 352 | }); 353 | }); 354 | apiFile.enums.forEach((k) => { 355 | messageMap[k.name] = 1; 356 | }); 357 | 358 | const code = format( 359 | genApiFileCode(apiFile, apiName, apiPrefixPath, messageMap) 360 | ); 361 | // const code = genApiFileCode(apiFile, apiName); 362 | result[apiFile.outputPath] = eslintDisable 363 | ? "/* eslint-disable */\n" + code 364 | : code; 365 | } 366 | return result; 367 | } 368 | -------------------------------------------------------------------------------- /common/google/api/http.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.api; 18 | 19 | option cc_enable_arenas = true; 20 | option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; 21 | option java_multiple_files = true; 22 | option java_outer_classname = "HttpProto"; 23 | option java_package = "com.google.api"; 24 | option objc_class_prefix = "GAPI"; 25 | 26 | 27 | // Defines the HTTP configuration for an API service. It contains a list of 28 | // [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method 29 | // to one or more HTTP REST API methods. 30 | message Http { 31 | // A list of HTTP configuration rules that apply to individual API methods. 32 | // 33 | // **NOTE:** All service configuration rules follow "last one wins" order. 34 | repeated HttpRule rules = 1; 35 | 36 | // When set to true, URL path parmeters will be fully URI-decoded except in 37 | // cases of single segment matches in reserved expansion, where "%2F" will be 38 | // left encoded. 39 | // 40 | // The default behavior is to not decode RFC 6570 reserved characters in multi 41 | // segment matches. 42 | bool fully_decode_reserved_expansion = 2; 43 | } 44 | 45 | // `HttpRule` defines the mapping of an RPC method to one or more HTTP 46 | // REST API methods. The mapping specifies how different portions of the RPC 47 | // request message are mapped to URL path, URL query parameters, and 48 | // HTTP request body. The mapping is typically specified as an 49 | // `google.api.http` annotation on the RPC method, 50 | // see "google/api/annotations.proto" for details. 51 | // 52 | // The mapping consists of a field specifying the path template and 53 | // method kind. The path template can refer to fields in the request 54 | // message, as in the example below which describes a REST GET 55 | // operation on a resource collection of messages: 56 | // 57 | // 58 | // service Messaging { 59 | // rpc GetMessage(GetMessageRequest) returns (Message) { 60 | // option (google.api.http).get = "/v1/messages/{message_id}/{sub.subfield}"; 61 | // } 62 | // } 63 | // message GetMessageRequest { 64 | // message SubMessage { 65 | // string subfield = 1; 66 | // } 67 | // string message_id = 1; // mapped to the URL 68 | // SubMessage sub = 2; // `sub.subfield` is url-mapped 69 | // } 70 | // message Message { 71 | // string text = 1; // content of the resource 72 | // } 73 | // 74 | // The same http annotation can alternatively be expressed inside the 75 | // `GRPC API Configuration` YAML file. 76 | // 77 | // http: 78 | // rules: 79 | // - selector: .Messaging.GetMessage 80 | // get: /v1/messages/{message_id}/{sub.subfield} 81 | // 82 | // This definition enables an automatic, bidrectional mapping of HTTP 83 | // JSON to RPC. Example: 84 | // 85 | // HTTP | RPC 86 | // -----|----- 87 | // `GET /v1/messages/123456/foo` | `GetMessage(message_id: "123456" sub: SubMessage(subfield: "foo"))` 88 | // 89 | // In general, not only fields but also field paths can be referenced 90 | // from a path pattern. Fields mapped to the path pattern cannot be 91 | // repeated and must have a primitive (non-message) type. 92 | // 93 | // Any fields in the request message which are not bound by the path 94 | // pattern automatically become (optional) HTTP query 95 | // parameters. Assume the following definition of the request message: 96 | // 97 | // 98 | // service Messaging { 99 | // rpc GetMessage(GetMessageRequest) returns (Message) { 100 | // option (google.api.http).get = "/v1/messages/{message_id}"; 101 | // } 102 | // } 103 | // message GetMessageRequest { 104 | // message SubMessage { 105 | // string subfield = 1; 106 | // } 107 | // string message_id = 1; // mapped to the URL 108 | // int64 revision = 2; // becomes a parameter 109 | // SubMessage sub = 3; // `sub.subfield` becomes a parameter 110 | // } 111 | // 112 | // 113 | // This enables a HTTP JSON to RPC mapping as below: 114 | // 115 | // HTTP | RPC 116 | // -----|----- 117 | // `GET /v1/messages/123456?revision=2&sub.subfield=foo` | `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: "foo"))` 118 | // 119 | // Note that fields which are mapped to HTTP parameters must have a 120 | // primitive type or a repeated primitive type. Message types are not 121 | // allowed. In the case of a repeated type, the parameter can be 122 | // repeated in the URL, as in `...?param=A¶m=B`. 123 | // 124 | // For HTTP method kinds which allow a request body, the `body` field 125 | // specifies the mapping. Consider a REST update method on the 126 | // message resource collection: 127 | // 128 | // 129 | // service Messaging { 130 | // rpc UpdateMessage(UpdateMessageRequest) returns (Message) { 131 | // option (google.api.http) = { 132 | // put: "/v1/messages/{message_id}" 133 | // body: "message" 134 | // }; 135 | // } 136 | // } 137 | // message UpdateMessageRequest { 138 | // string message_id = 1; // mapped to the URL 139 | // Message message = 2; // mapped to the body 140 | // } 141 | // 142 | // 143 | // The following HTTP JSON to RPC mapping is enabled, where the 144 | // representation of the JSON in the request body is determined by 145 | // protos JSON encoding: 146 | // 147 | // HTTP | RPC 148 | // -----|----- 149 | // `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" message { text: "Hi!" })` 150 | // 151 | // The special name `*` can be used in the body mapping to define that 152 | // every field not bound by the path template should be mapped to the 153 | // request body. This enables the following alternative definition of 154 | // the update method: 155 | // 156 | // service Messaging { 157 | // rpc UpdateMessage(Message) returns (Message) { 158 | // option (google.api.http) = { 159 | // put: "/v1/messages/{message_id}" 160 | // body: "*" 161 | // }; 162 | // } 163 | // } 164 | // message Message { 165 | // string message_id = 1; 166 | // string text = 2; 167 | // } 168 | // 169 | // 170 | // The following HTTP JSON to RPC mapping is enabled: 171 | // 172 | // HTTP | RPC 173 | // -----|----- 174 | // `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" text: "Hi!")` 175 | // 176 | // Note that when using `*` in the body mapping, it is not possible to 177 | // have HTTP parameters, as all fields not bound by the path end in 178 | // the body. This makes this option more rarely used in practice of 179 | // defining REST APIs. The common usage of `*` is in custom methods 180 | // which don't use the URL at all for transferring data. 181 | // 182 | // It is possible to define multiple HTTP methods for one RPC by using 183 | // the `additional_bindings` option. Example: 184 | // 185 | // service Messaging { 186 | // rpc GetMessage(GetMessageRequest) returns (Message) { 187 | // option (google.api.http) = { 188 | // get: "/v1/messages/{message_id}" 189 | // additional_bindings { 190 | // get: "/v1/users/{user_id}/messages/{message_id}" 191 | // } 192 | // }; 193 | // } 194 | // } 195 | // message GetMessageRequest { 196 | // string message_id = 1; 197 | // string user_id = 2; 198 | // } 199 | // 200 | // 201 | // This enables the following two alternative HTTP JSON to RPC 202 | // mappings: 203 | // 204 | // HTTP | RPC 205 | // -----|----- 206 | // `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` 207 | // `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: "123456")` 208 | // 209 | // # Rules for HTTP mapping 210 | // 211 | // The rules for mapping HTTP path, query parameters, and body fields 212 | // to the request message are as follows: 213 | // 214 | // 1. The `body` field specifies either `*` or a field path, or is 215 | // omitted. If omitted, it indicates there is no HTTP request body. 216 | // 2. Leaf fields (recursive expansion of nested messages in the 217 | // request) can be classified into three types: 218 | // (a) Matched in the URL template. 219 | // (b) Covered by body (if body is `*`, everything except (a) fields; 220 | // else everything under the body field) 221 | // (c) All other fields. 222 | // 3. URL query parameters found in the HTTP request are mapped to (c) fields. 223 | // 4. Any body sent with an HTTP request can contain only (b) fields. 224 | // 225 | // The syntax of the path template is as follows: 226 | // 227 | // Template = "/" Segments [ Verb ] ; 228 | // Segments = Segment { "/" Segment } ; 229 | // Segment = "*" | "**" | LITERAL | Variable ; 230 | // Variable = "{" FieldPath [ "=" Segments ] "}" ; 231 | // FieldPath = IDENT { "." IDENT } ; 232 | // Verb = ":" LITERAL ; 233 | // 234 | // The syntax `*` matches a single path segment. The syntax `**` matches zero 235 | // or more path segments, which must be the last part of the path except the 236 | // `Verb`. The syntax `LITERAL` matches literal text in the path. 237 | // 238 | // The syntax `Variable` matches part of the URL path as specified by its 239 | // template. A variable template must not contain other variables. If a variable 240 | // matches a single path segment, its template may be omitted, e.g. `{var}` 241 | // is equivalent to `{var=*}`. 242 | // 243 | // If a variable contains exactly one path segment, such as `"{var}"` or 244 | // `"{var=*}"`, when such a variable is expanded into a URL path, all characters 245 | // except `[-_.~0-9a-zA-Z]` are percent-encoded. Such variables show up in the 246 | // Discovery Document as `{var}`. 247 | // 248 | // If a variable contains one or more path segments, such as `"{var=foo/*}"` 249 | // or `"{var=**}"`, when such a variable is expanded into a URL path, all 250 | // characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. Such variables 251 | // show up in the Discovery Document as `{+var}`. 252 | // 253 | // NOTE: While the single segment variable matches the semantics of 254 | // [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 255 | // Simple String Expansion, the multi segment variable **does not** match 256 | // RFC 6570 Reserved Expansion. The reason is that the Reserved Expansion 257 | // does not expand special characters like `?` and `#`, which would lead 258 | // to invalid URLs. 259 | // 260 | // NOTE: the field paths in variables and in the `body` must not refer to 261 | // repeated fields or map fields. 262 | message HttpRule { 263 | // Selects methods to which this rule applies. 264 | // 265 | // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. 266 | string selector = 1; 267 | 268 | // Determines the URL pattern is matched by this rules. This pattern can be 269 | // used with any of the {get|put|post|delete|patch} methods. A custom method 270 | // can be defined using the 'custom' field. 271 | oneof pattern { 272 | // Used for listing and getting information about resources. 273 | string get = 2; 274 | 275 | // Used for updating a resource. 276 | string put = 3; 277 | 278 | // Used for creating a resource. 279 | string post = 4; 280 | 281 | // Used for deleting a resource. 282 | string delete = 5; 283 | 284 | // Used for updating a resource. 285 | string patch = 6; 286 | 287 | // The custom pattern is used for specifying an HTTP method that is not 288 | // included in the `pattern` field, such as HEAD, or "*" to leave the 289 | // HTTP method unspecified for this rule. The wild-card rule is useful 290 | // for services that provide content to Web (HTML) clients. 291 | CustomHttpPattern custom = 8; 292 | } 293 | 294 | // The name of the request field whose value is mapped to the HTTP body, or 295 | // `*` for mapping all fields not captured by the path pattern to the HTTP 296 | // body. NOTE: the referred field must not be a repeated field and must be 297 | // present at the top-level of request message type. 298 | string body = 7; 299 | 300 | // Optional. The name of the response field whose value is mapped to the HTTP 301 | // body of response. Other response fields are ignored. When 302 | // not set, the response message will be used as HTTP body of response. 303 | string response_body = 12; 304 | 305 | // Additional HTTP bindings for the selector. Nested bindings must 306 | // not contain an `additional_bindings` field themselves (that is, 307 | // the nesting may only be one level deep). 308 | repeated HttpRule additional_bindings = 11; 309 | } 310 | 311 | // A custom pattern is used for defining custom HTTP verb. 312 | message CustomHttpPattern { 313 | // The name of this custom HTTP verb. 314 | string kind = 1; 315 | 316 | // The path matched by this custom verb. 317 | string path = 2; 318 | } 319 | -------------------------------------------------------------------------------- /common/google/protobuf/descriptor.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | // Author: kenton@google.com (Kenton Varda) 32 | // Based on original Protocol Buffers design by 33 | // Sanjay Ghemawat, Jeff Dean, and others. 34 | // 35 | // The messages in this file describe the definitions found in .proto files. 36 | // A valid .proto file can be translated directly to a FileDescriptorProto 37 | // without any other information (e.g. without reading its imports). 38 | 39 | 40 | syntax = "proto2"; 41 | 42 | package google.protobuf; 43 | 44 | option go_package = "github.com/golang/protobuf/protoc-gen-go/descriptor;descriptor"; 45 | option java_package = "com.google.protobuf"; 46 | option java_outer_classname = "DescriptorProtos"; 47 | option csharp_namespace = "Google.Protobuf.Reflection"; 48 | option objc_class_prefix = "GPB"; 49 | option cc_enable_arenas = true; 50 | 51 | // descriptor.proto must be optimized for speed because reflection-based 52 | // algorithms don't work during bootstrapping. 53 | option optimize_for = SPEED; 54 | 55 | // The protocol compiler can output a FileDescriptorSet containing the .proto 56 | // files it parses. 57 | message FileDescriptorSet { 58 | repeated FileDescriptorProto file = 1; 59 | } 60 | 61 | // Describes a complete .proto file. 62 | message FileDescriptorProto { 63 | optional string name = 1; // file name, relative to root of source tree 64 | optional string package = 2; // e.g. "foo", "foo.bar", etc. 65 | 66 | // Names of files imported by this file. 67 | repeated string dependency = 3; 68 | // Indexes of the public imported files in the dependency list above. 69 | repeated int32 public_dependency = 10; 70 | // Indexes of the weak imported files in the dependency list. 71 | // For Google-internal migration only. Do not use. 72 | repeated int32 weak_dependency = 11; 73 | 74 | // All top-level definitions in this file. 75 | repeated DescriptorProto message_type = 4; 76 | repeated EnumDescriptorProto enum_type = 5; 77 | repeated ServiceDescriptorProto service = 6; 78 | repeated FieldDescriptorProto extension = 7; 79 | 80 | optional FileOptions options = 8; 81 | 82 | // This field contains optional information about the original source code. 83 | // You may safely remove this entire field without harming runtime 84 | // functionality of the descriptors -- the information is needed only by 85 | // development tools. 86 | optional SourceCodeInfo source_code_info = 9; 87 | 88 | // The syntax of the proto file. 89 | // The supported values are "proto2" and "proto3". 90 | optional string syntax = 12; 91 | } 92 | 93 | // Describes a message type. 94 | message DescriptorProto { 95 | optional string name = 1; 96 | 97 | repeated FieldDescriptorProto field = 2; 98 | repeated FieldDescriptorProto extension = 6; 99 | 100 | repeated DescriptorProto nested_type = 3; 101 | repeated EnumDescriptorProto enum_type = 4; 102 | 103 | message ExtensionRange { 104 | optional int32 start = 1; // Inclusive. 105 | optional int32 end = 2; // Exclusive. 106 | 107 | optional ExtensionRangeOptions options = 3; 108 | } 109 | repeated ExtensionRange extension_range = 5; 110 | 111 | repeated OneofDescriptorProto oneof_decl = 8; 112 | 113 | optional MessageOptions options = 7; 114 | 115 | // Range of reserved tag numbers. Reserved tag numbers may not be used by 116 | // fields or extension ranges in the same message. Reserved ranges may 117 | // not overlap. 118 | message ReservedRange { 119 | optional int32 start = 1; // Inclusive. 120 | optional int32 end = 2; // Exclusive. 121 | } 122 | repeated ReservedRange reserved_range = 9; 123 | // Reserved field names, which may not be used by fields in the same message. 124 | // A given name may only be reserved once. 125 | repeated string reserved_name = 10; 126 | } 127 | 128 | message ExtensionRangeOptions { 129 | // The parser stores options it doesn't recognize here. See above. 130 | repeated UninterpretedOption uninterpreted_option = 999; 131 | 132 | // Clients can define custom options in extensions of this message. See above. 133 | extensions 1000 to max; 134 | } 135 | 136 | // Describes a field within a message. 137 | message FieldDescriptorProto { 138 | enum Type { 139 | // 0 is reserved for errors. 140 | // Order is weird for historical reasons. 141 | TYPE_DOUBLE = 1; 142 | TYPE_FLOAT = 2; 143 | // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if 144 | // negative values are likely. 145 | TYPE_INT64 = 3; 146 | TYPE_UINT64 = 4; 147 | // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if 148 | // negative values are likely. 149 | TYPE_INT32 = 5; 150 | TYPE_FIXED64 = 6; 151 | TYPE_FIXED32 = 7; 152 | TYPE_BOOL = 8; 153 | TYPE_STRING = 9; 154 | // Tag-delimited aggregate. 155 | // Group type is deprecated and not supported in proto3. However, Proto3 156 | // implementations should still be able to parse the group wire format and 157 | // treat group fields as unknown fields. 158 | TYPE_GROUP = 10; 159 | TYPE_MESSAGE = 11; // Length-delimited aggregate. 160 | 161 | // New in version 2. 162 | TYPE_BYTES = 12; 163 | TYPE_UINT32 = 13; 164 | TYPE_ENUM = 14; 165 | TYPE_SFIXED32 = 15; 166 | TYPE_SFIXED64 = 16; 167 | TYPE_SINT32 = 17; // Uses ZigZag encoding. 168 | TYPE_SINT64 = 18; // Uses ZigZag encoding. 169 | } 170 | 171 | enum Label { 172 | // 0 is reserved for errors 173 | LABEL_OPTIONAL = 1; 174 | LABEL_REQUIRED = 2; 175 | LABEL_REPEATED = 3; 176 | } 177 | 178 | optional string name = 1; 179 | optional int32 number = 3; 180 | optional Label label = 4; 181 | 182 | // If type_name is set, this need not be set. If both this and type_name 183 | // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. 184 | optional Type type = 5; 185 | 186 | // For message and enum types, this is the name of the type. If the name 187 | // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping 188 | // rules are used to find the type (i.e. first the nested types within this 189 | // message are searched, then within the parent, on up to the root 190 | // namespace). 191 | optional string type_name = 6; 192 | 193 | // For extensions, this is the name of the type being extended. It is 194 | // resolved in the same manner as type_name. 195 | optional string extendee = 2; 196 | 197 | // For numeric types, contains the original text representation of the value. 198 | // For booleans, "true" or "false". 199 | // For strings, contains the default text contents (not escaped in any way). 200 | // For bytes, contains the C escaped value. All bytes >= 128 are escaped. 201 | // TODO(kenton): Base-64 encode? 202 | optional string default_value = 7; 203 | 204 | // If set, gives the index of a oneof in the containing type's oneof_decl 205 | // list. This field is a member of that oneof. 206 | optional int32 oneof_index = 9; 207 | 208 | // JSON name of this field. The value is set by protocol compiler. If the 209 | // user has set a "json_name" option on this field, that option's value 210 | // will be used. Otherwise, it's deduced from the field's name by converting 211 | // it to camelCase. 212 | optional string json_name = 10; 213 | 214 | optional FieldOptions options = 8; 215 | } 216 | 217 | // Describes a oneof. 218 | message OneofDescriptorProto { 219 | optional string name = 1; 220 | optional OneofOptions options = 2; 221 | } 222 | 223 | // Describes an enum type. 224 | message EnumDescriptorProto { 225 | optional string name = 1; 226 | 227 | repeated EnumValueDescriptorProto value = 2; 228 | 229 | optional EnumOptions options = 3; 230 | 231 | // Range of reserved numeric values. Reserved values may not be used by 232 | // entries in the same enum. Reserved ranges may not overlap. 233 | // 234 | // Note that this is distinct from DescriptorProto.ReservedRange in that it 235 | // is inclusive such that it can appropriately represent the entire int32 236 | // domain. 237 | message EnumReservedRange { 238 | optional int32 start = 1; // Inclusive. 239 | optional int32 end = 2; // Inclusive. 240 | } 241 | 242 | // Range of reserved numeric values. Reserved numeric values may not be used 243 | // by enum values in the same enum declaration. Reserved ranges may not 244 | // overlap. 245 | repeated EnumReservedRange reserved_range = 4; 246 | 247 | // Reserved enum value names, which may not be reused. A given name may only 248 | // be reserved once. 249 | repeated string reserved_name = 5; 250 | } 251 | 252 | // Describes a value within an enum. 253 | message EnumValueDescriptorProto { 254 | optional string name = 1; 255 | optional int32 number = 2; 256 | 257 | optional EnumValueOptions options = 3; 258 | } 259 | 260 | // Describes a service. 261 | message ServiceDescriptorProto { 262 | optional string name = 1; 263 | repeated MethodDescriptorProto method = 2; 264 | 265 | optional ServiceOptions options = 3; 266 | } 267 | 268 | // Describes a method of a service. 269 | message MethodDescriptorProto { 270 | optional string name = 1; 271 | 272 | // Input and output type names. These are resolved in the same way as 273 | // FieldDescriptorProto.type_name, but must refer to a message type. 274 | optional string input_type = 2; 275 | optional string output_type = 3; 276 | 277 | optional MethodOptions options = 4; 278 | 279 | // Identifies if client streams multiple client messages 280 | optional bool client_streaming = 5 [default = false]; 281 | // Identifies if server streams multiple server messages 282 | optional bool server_streaming = 6 [default = false]; 283 | } 284 | 285 | 286 | // =================================================================== 287 | // Options 288 | 289 | // Each of the definitions above may have "options" attached. These are 290 | // just annotations which may cause code to be generated slightly differently 291 | // or may contain hints for code that manipulates protocol messages. 292 | // 293 | // Clients may define custom options as extensions of the *Options messages. 294 | // These extensions may not yet be known at parsing time, so the parser cannot 295 | // store the values in them. Instead it stores them in a field in the *Options 296 | // message called uninterpreted_option. This field must have the same name 297 | // across all *Options messages. We then use this field to populate the 298 | // extensions when we build a descriptor, at which point all protos have been 299 | // parsed and so all extensions are known. 300 | // 301 | // Extension numbers for custom options may be chosen as follows: 302 | // * For options which will only be used within a single application or 303 | // organization, or for experimental options, use field numbers 50000 304 | // through 99999. It is up to you to ensure that you do not use the 305 | // same number for multiple options. 306 | // * For options which will be published and used publicly by multiple 307 | // independent entities, e-mail protobuf-global-extension-registry@google.com 308 | // to reserve extension numbers. Simply provide your project name (e.g. 309 | // Objective-C plugin) and your project website (if available) -- there's no 310 | // need to explain how you intend to use them. Usually you only need one 311 | // extension number. You can declare multiple options with only one extension 312 | // number by putting them in a sub-message. See the Custom Options section of 313 | // the docs for examples: 314 | // https://developers.google.com/protocol-buffers/docs/proto#options 315 | // If this turns out to be popular, a web service will be set up 316 | // to automatically assign option numbers. 317 | 318 | message FileOptions { 319 | 320 | // Sets the Java package where classes generated from this .proto will be 321 | // placed. By default, the proto package is used, but this is often 322 | // inappropriate because proto packages do not normally start with backwards 323 | // domain names. 324 | optional string java_package = 1; 325 | 326 | 327 | // If set, all the classes from the .proto file are wrapped in a single 328 | // outer class with the given name. This applies to both Proto1 329 | // (equivalent to the old "--one_java_file" option) and Proto2 (where 330 | // a .proto always translates to a single class, but you may want to 331 | // explicitly choose the class name). 332 | optional string java_outer_classname = 8; 333 | 334 | // If set true, then the Java code generator will generate a separate .java 335 | // file for each top-level message, enum, and service defined in the .proto 336 | // file. Thus, these types will *not* be nested inside the outer class 337 | // named by java_outer_classname. However, the outer class will still be 338 | // generated to contain the file's getDescriptor() method as well as any 339 | // top-level extensions defined in the file. 340 | optional bool java_multiple_files = 10 [default = false]; 341 | 342 | // This option does nothing. 343 | optional bool java_generate_equals_and_hash = 20 [deprecated=true]; 344 | 345 | // If set true, then the Java2 code generator will generate code that 346 | // throws an exception whenever an attempt is made to assign a non-UTF-8 347 | // byte sequence to a string field. 348 | // Message reflection will do the same. 349 | // However, an extension field still accepts non-UTF-8 byte sequences. 350 | // This option has no effect on when used with the lite runtime. 351 | optional bool java_string_check_utf8 = 27 [default = false]; 352 | 353 | 354 | // Generated classes can be optimized for speed or code size. 355 | enum OptimizeMode { 356 | SPEED = 1; // Generate complete code for parsing, serialization, 357 | // etc. 358 | CODE_SIZE = 2; // Use ReflectionOps to implement these methods. 359 | LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. 360 | } 361 | optional OptimizeMode optimize_for = 9 [default = SPEED]; 362 | 363 | // Sets the Go package where structs generated from this .proto will be 364 | // placed. If omitted, the Go package will be derived from the following: 365 | // - The basename of the package import path, if provided. 366 | // - Otherwise, the package statement in the .proto file, if present. 367 | // - Otherwise, the basename of the .proto file, without extension. 368 | optional string go_package = 11; 369 | 370 | 371 | 372 | 373 | // Should generic services be generated in each language? "Generic" services 374 | // are not specific to any particular RPC system. They are generated by the 375 | // main code generators in each language (without additional plugins). 376 | // Generic services were the only kind of service generation supported by 377 | // early versions of google.protobuf. 378 | // 379 | // Generic services are now considered deprecated in favor of using plugins 380 | // that generate code specific to your particular RPC system. Therefore, 381 | // these default to false. Old code which depends on generic services should 382 | // explicitly set them to true. 383 | optional bool cc_generic_services = 16 [default = false]; 384 | optional bool java_generic_services = 17 [default = false]; 385 | optional bool py_generic_services = 18 [default = false]; 386 | optional bool php_generic_services = 42 [default = false]; 387 | 388 | // Is this file deprecated? 389 | // Depending on the target platform, this can emit Deprecated annotations 390 | // for everything in the file, or it will be completely ignored; in the very 391 | // least, this is a formalization for deprecating files. 392 | optional bool deprecated = 23 [default = false]; 393 | 394 | // Enables the use of arenas for the proto messages in this file. This applies 395 | // only to generated classes for C++. 396 | optional bool cc_enable_arenas = 31 [default = false]; 397 | 398 | 399 | // Sets the objective c class prefix which is prepended to all objective c 400 | // generated classes from this .proto. There is no default. 401 | optional string objc_class_prefix = 36; 402 | 403 | // Namespace for generated classes; defaults to the package. 404 | optional string csharp_namespace = 37; 405 | 406 | // By default Swift generators will take the proto package and CamelCase it 407 | // replacing '.' with underscore and use that to prefix the types/symbols 408 | // defined. When this options is provided, they will use this value instead 409 | // to prefix the types/symbols defined. 410 | optional string swift_prefix = 39; 411 | 412 | // Sets the php class prefix which is prepended to all php generated classes 413 | // from this .proto. Default is empty. 414 | optional string php_class_prefix = 40; 415 | 416 | // Use this option to change the namespace of php generated classes. Default 417 | // is empty. When this option is empty, the package name will be used for 418 | // determining the namespace. 419 | optional string php_namespace = 41; 420 | 421 | // Use this option to change the namespace of php generated metadata classes. 422 | // Default is empty. When this option is empty, the proto file name will be 423 | // used for determining the namespace. 424 | optional string php_metadata_namespace = 44; 425 | 426 | // Use this option to change the package of ruby generated classes. Default 427 | // is empty. When this option is not set, the package name will be used for 428 | // determining the ruby package. 429 | optional string ruby_package = 45; 430 | 431 | 432 | // The parser stores options it doesn't recognize here. 433 | // See the documentation for the "Options" section above. 434 | repeated UninterpretedOption uninterpreted_option = 999; 435 | 436 | // Clients can define custom options in extensions of this message. 437 | // See the documentation for the "Options" section above. 438 | extensions 1000 to max; 439 | 440 | reserved 38; 441 | } 442 | 443 | message MessageOptions { 444 | // Set true to use the old proto1 MessageSet wire format for extensions. 445 | // This is provided for backwards-compatibility with the MessageSet wire 446 | // format. You should not use this for any other reason: It's less 447 | // efficient, has fewer features, and is more complicated. 448 | // 449 | // The message must be defined exactly as follows: 450 | // message Foo { 451 | // option message_set_wire_format = true; 452 | // extensions 4 to max; 453 | // } 454 | // Note that the message cannot have any defined fields; MessageSets only 455 | // have extensions. 456 | // 457 | // All extensions of your type must be singular messages; e.g. they cannot 458 | // be int32s, enums, or repeated messages. 459 | // 460 | // Because this is an option, the above two restrictions are not enforced by 461 | // the protocol compiler. 462 | optional bool message_set_wire_format = 1 [default = false]; 463 | 464 | // Disables the generation of the standard "descriptor()" accessor, which can 465 | // conflict with a field of the same name. This is meant to make migration 466 | // from proto1 easier; new code should avoid fields named "descriptor". 467 | optional bool no_standard_descriptor_accessor = 2 [default = false]; 468 | 469 | // Is this message deprecated? 470 | // Depending on the target platform, this can emit Deprecated annotations 471 | // for the message, or it will be completely ignored; in the very least, 472 | // this is a formalization for deprecating messages. 473 | optional bool deprecated = 3 [default = false]; 474 | 475 | // Whether the message is an automatically generated map entry type for the 476 | // maps field. 477 | // 478 | // For maps fields: 479 | // map map_field = 1; 480 | // The parsed descriptor looks like: 481 | // message MapFieldEntry { 482 | // option map_entry = true; 483 | // optional KeyType key = 1; 484 | // optional ValueType value = 2; 485 | // } 486 | // repeated MapFieldEntry map_field = 1; 487 | // 488 | // Implementations may choose not to generate the map_entry=true message, but 489 | // use a native map in the target language to hold the keys and values. 490 | // The reflection APIs in such implementations still need to work as 491 | // if the field is a repeated message field. 492 | // 493 | // NOTE: Do not set the option in .proto files. Always use the maps syntax 494 | // instead. The option should only be implicitly set by the proto compiler 495 | // parser. 496 | optional bool map_entry = 7; 497 | 498 | reserved 8; // javalite_serializable 499 | reserved 9; // javanano_as_lite 500 | 501 | 502 | // The parser stores options it doesn't recognize here. See above. 503 | repeated UninterpretedOption uninterpreted_option = 999; 504 | 505 | // Clients can define custom options in extensions of this message. See above. 506 | extensions 1000 to max; 507 | } 508 | 509 | message FieldOptions { 510 | // The ctype option instructs the C++ code generator to use a different 511 | // representation of the field than it normally would. See the specific 512 | // options below. This option is not yet implemented in the open source 513 | // release -- sorry, we'll try to include it in a future version! 514 | optional CType ctype = 1 [default = STRING]; 515 | enum CType { 516 | // Default mode. 517 | STRING = 0; 518 | 519 | CORD = 1; 520 | 521 | STRING_PIECE = 2; 522 | } 523 | // The packed option can be enabled for repeated primitive fields to enable 524 | // a more efficient representation on the wire. Rather than repeatedly 525 | // writing the tag and type for each element, the entire array is encoded as 526 | // a single length-delimited blob. In proto3, only explicit setting it to 527 | // false will avoid using packed encoding. 528 | optional bool packed = 2; 529 | 530 | // The jstype option determines the JavaScript type used for values of the 531 | // field. The option is permitted only for 64 bit integral and fixed types 532 | // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING 533 | // is represented as JavaScript string, which avoids loss of precision that 534 | // can happen when a large value is converted to a floating point JavaScript. 535 | // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to 536 | // use the JavaScript "number" type. The behavior of the default option 537 | // JS_NORMAL is implementation dependent. 538 | // 539 | // This option is an enum to permit additional types to be added, e.g. 540 | // goog.math.Integer. 541 | optional JSType jstype = 6 [default = JS_NORMAL]; 542 | enum JSType { 543 | // Use the default type. 544 | JS_NORMAL = 0; 545 | 546 | // Use JavaScript strings. 547 | JS_STRING = 1; 548 | 549 | // Use JavaScript numbers. 550 | JS_NUMBER = 2; 551 | } 552 | 553 | // Should this field be parsed lazily? Lazy applies only to message-type 554 | // fields. It means that when the outer message is initially parsed, the 555 | // inner message's contents will not be parsed but instead stored in encoded 556 | // form. The inner message will actually be parsed when it is first accessed. 557 | // 558 | // This is only a hint. Implementations are free to choose whether to use 559 | // eager or lazy parsing regardless of the value of this option. However, 560 | // setting this option true suggests that the protocol author believes that 561 | // using lazy parsing on this field is worth the additional bookkeeping 562 | // overhead typically needed to implement it. 563 | // 564 | // This option does not affect the public interface of any generated code; 565 | // all method signatures remain the same. Furthermore, thread-safety of the 566 | // interface is not affected by this option; const methods remain safe to 567 | // call from multiple threads concurrently, while non-const methods continue 568 | // to require exclusive access. 569 | // 570 | // 571 | // Note that implementations may choose not to check required fields within 572 | // a lazy sub-message. That is, calling IsInitialized() on the outer message 573 | // may return true even if the inner message has missing required fields. 574 | // This is necessary because otherwise the inner message would have to be 575 | // parsed in order to perform the check, defeating the purpose of lazy 576 | // parsing. An implementation which chooses not to check required fields 577 | // must be consistent about it. That is, for any particular sub-message, the 578 | // implementation must either *always* check its required fields, or *never* 579 | // check its required fields, regardless of whether or not the message has 580 | // been parsed. 581 | optional bool lazy = 5 [default = false]; 582 | 583 | // Is this field deprecated? 584 | // Depending on the target platform, this can emit Deprecated annotations 585 | // for accessors, or it will be completely ignored; in the very least, this 586 | // is a formalization for deprecating fields. 587 | optional bool deprecated = 3 [default = false]; 588 | 589 | // For Google-internal migration only. Do not use. 590 | optional bool weak = 10 [default = false]; 591 | 592 | 593 | // The parser stores options it doesn't recognize here. See above. 594 | repeated UninterpretedOption uninterpreted_option = 999; 595 | 596 | // Clients can define custom options in extensions of this message. See above. 597 | extensions 1000 to max; 598 | 599 | reserved 4; // removed jtype 600 | } 601 | 602 | message OneofOptions { 603 | // The parser stores options it doesn't recognize here. See above. 604 | repeated UninterpretedOption uninterpreted_option = 999; 605 | 606 | // Clients can define custom options in extensions of this message. See above. 607 | extensions 1000 to max; 608 | } 609 | 610 | message EnumOptions { 611 | 612 | // Set this option to true to allow mapping different tag names to the same 613 | // value. 614 | optional bool allow_alias = 2; 615 | 616 | // Is this enum deprecated? 617 | // Depending on the target platform, this can emit Deprecated annotations 618 | // for the enum, or it will be completely ignored; in the very least, this 619 | // is a formalization for deprecating enums. 620 | optional bool deprecated = 3 [default = false]; 621 | 622 | reserved 5; // javanano_as_lite 623 | 624 | // The parser stores options it doesn't recognize here. See above. 625 | repeated UninterpretedOption uninterpreted_option = 999; 626 | 627 | // Clients can define custom options in extensions of this message. See above. 628 | extensions 1000 to max; 629 | } 630 | 631 | message EnumValueOptions { 632 | // Is this enum value deprecated? 633 | // Depending on the target platform, this can emit Deprecated annotations 634 | // for the enum value, or it will be completely ignored; in the very least, 635 | // this is a formalization for deprecating enum values. 636 | optional bool deprecated = 1 [default = false]; 637 | 638 | // The parser stores options it doesn't recognize here. See above. 639 | repeated UninterpretedOption uninterpreted_option = 999; 640 | 641 | // Clients can define custom options in extensions of this message. See above. 642 | extensions 1000 to max; 643 | } 644 | 645 | message ServiceOptions { 646 | 647 | // Note: Field numbers 1 through 32 are reserved for Google's internal RPC 648 | // framework. We apologize for hoarding these numbers to ourselves, but 649 | // we were already using them long before we decided to release Protocol 650 | // Buffers. 651 | 652 | // Is this service deprecated? 653 | // Depending on the target platform, this can emit Deprecated annotations 654 | // for the service, or it will be completely ignored; in the very least, 655 | // this is a formalization for deprecating services. 656 | optional bool deprecated = 33 [default = false]; 657 | 658 | // The parser stores options it doesn't recognize here. See above. 659 | repeated UninterpretedOption uninterpreted_option = 999; 660 | 661 | // Clients can define custom options in extensions of this message. See above. 662 | extensions 1000 to max; 663 | } 664 | 665 | message MethodOptions { 666 | 667 | // Note: Field numbers 1 through 32 are reserved for Google's internal RPC 668 | // framework. We apologize for hoarding these numbers to ourselves, but 669 | // we were already using them long before we decided to release Protocol 670 | // Buffers. 671 | 672 | // Is this method deprecated? 673 | // Depending on the target platform, this can emit Deprecated annotations 674 | // for the method, or it will be completely ignored; in the very least, 675 | // this is a formalization for deprecating methods. 676 | optional bool deprecated = 33 [default = false]; 677 | 678 | // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, 679 | // or neither? HTTP based RPC implementation may choose GET verb for safe 680 | // methods, and PUT verb for idempotent methods instead of the default POST. 681 | enum IdempotencyLevel { 682 | IDEMPOTENCY_UNKNOWN = 0; 683 | NO_SIDE_EFFECTS = 1; // implies idempotent 684 | IDEMPOTENT = 2; // idempotent, but may have side effects 685 | } 686 | optional IdempotencyLevel idempotency_level = 34 687 | [default = IDEMPOTENCY_UNKNOWN]; 688 | 689 | // The parser stores options it doesn't recognize here. See above. 690 | repeated UninterpretedOption uninterpreted_option = 999; 691 | 692 | // Clients can define custom options in extensions of this message. See above. 693 | extensions 1000 to max; 694 | } 695 | 696 | 697 | // A message representing a option the parser does not recognize. This only 698 | // appears in options protos created by the compiler::Parser class. 699 | // DescriptorPool resolves these when building Descriptor objects. Therefore, 700 | // options protos in descriptor objects (e.g. returned by Descriptor::options(), 701 | // or produced by Descriptor::CopyTo()) will never have UninterpretedOptions 702 | // in them. 703 | message UninterpretedOption { 704 | // The name of the uninterpreted option. Each string represents a segment in 705 | // a dot-separated name. is_extension is true iff a segment represents an 706 | // extension (denoted with parentheses in options specs in .proto files). 707 | // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents 708 | // "foo.(bar.baz).qux". 709 | message NamePart { 710 | required string name_part = 1; 711 | required bool is_extension = 2; 712 | } 713 | repeated NamePart name = 2; 714 | 715 | // The value of the uninterpreted option, in whatever type the tokenizer 716 | // identified it as during parsing. Exactly one of these should be set. 717 | optional string identifier_value = 3; 718 | optional uint64 positive_int_value = 4; 719 | optional int64 negative_int_value = 5; 720 | optional double double_value = 6; 721 | optional bytes string_value = 7; 722 | optional string aggregate_value = 8; 723 | } 724 | 725 | // =================================================================== 726 | // Optional source code info 727 | 728 | // Encapsulates information about the original source file from which a 729 | // FileDescriptorProto was generated. 730 | message SourceCodeInfo { 731 | // A Location identifies a piece of source code in a .proto file which 732 | // corresponds to a particular definition. This information is intended 733 | // to be useful to IDEs, code indexers, documentation generators, and similar 734 | // tools. 735 | // 736 | // For example, say we have a file like: 737 | // message Foo { 738 | // optional string foo = 1; 739 | // } 740 | // Let's look at just the field definition: 741 | // optional string foo = 1; 742 | // ^ ^^ ^^ ^ ^^^ 743 | // a bc de f ghi 744 | // We have the following locations: 745 | // span path represents 746 | // [a,i) [ 4, 0, 2, 0 ] The whole field definition. 747 | // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). 748 | // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). 749 | // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). 750 | // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). 751 | // 752 | // Notes: 753 | // - A location may refer to a repeated field itself (i.e. not to any 754 | // particular index within it). This is used whenever a set of elements are 755 | // logically enclosed in a single code segment. For example, an entire 756 | // extend block (possibly containing multiple extension definitions) will 757 | // have an outer location whose path refers to the "extensions" repeated 758 | // field without an index. 759 | // - Multiple locations may have the same path. This happens when a single 760 | // logical declaration is spread out across multiple places. The most 761 | // obvious example is the "extend" block again -- there may be multiple 762 | // extend blocks in the same scope, each of which will have the same path. 763 | // - A location's span is not always a subset of its parent's span. For 764 | // example, the "extendee" of an extension declaration appears at the 765 | // beginning of the "extend" block and is shared by all extensions within 766 | // the block. 767 | // - Just because a location's span is a subset of some other location's span 768 | // does not mean that it is a descendant. For example, a "group" defines 769 | // both a type and a field in a single declaration. Thus, the locations 770 | // corresponding to the type and field and their components will overlap. 771 | // - Code which tries to interpret locations should probably be designed to 772 | // ignore those that it doesn't understand, as more types of locations could 773 | // be recorded in the future. 774 | repeated Location location = 1; 775 | message Location { 776 | // Identifies which part of the FileDescriptorProto was defined at this 777 | // location. 778 | // 779 | // Each element is a field number or an index. They form a path from 780 | // the root FileDescriptorProto to the place where the definition. For 781 | // example, this path: 782 | // [ 4, 3, 2, 7, 1 ] 783 | // refers to: 784 | // file.message_type(3) // 4, 3 785 | // .field(7) // 2, 7 786 | // .name() // 1 787 | // This is because FileDescriptorProto.message_type has field number 4: 788 | // repeated DescriptorProto message_type = 4; 789 | // and DescriptorProto.field has field number 2: 790 | // repeated FieldDescriptorProto field = 2; 791 | // and FieldDescriptorProto.name has field number 1: 792 | // optional string name = 1; 793 | // 794 | // Thus, the above path gives the location of a field name. If we removed 795 | // the last element: 796 | // [ 4, 3, 2, 7 ] 797 | // this path refers to the whole field declaration (from the beginning 798 | // of the label to the terminating semicolon). 799 | repeated int32 path = 1 [packed = true]; 800 | 801 | // Always has exactly three or four elements: start line, start column, 802 | // end line (optional, otherwise assumed same as start line), end column. 803 | // These are packed into a single field for efficiency. Note that line 804 | // and column numbers are zero-based -- typically you will want to add 805 | // 1 to each before displaying to a user. 806 | repeated int32 span = 2 [packed = true]; 807 | 808 | // If this SourceCodeInfo represents a complete declaration, these are any 809 | // comments appearing before and after the declaration which appear to be 810 | // attached to the declaration. 811 | // 812 | // A series of line comments appearing on consecutive lines, with no other 813 | // tokens appearing on those lines, will be treated as a single comment. 814 | // 815 | // leading_detached_comments will keep paragraphs of comments that appear 816 | // before (but not connected to) the current element. Each paragraph, 817 | // separated by empty lines, will be one comment element in the repeated 818 | // field. 819 | // 820 | // Only the comment content is provided; comment markers (e.g. //) are 821 | // stripped out. For block comments, leading whitespace and an asterisk 822 | // will be stripped from the beginning of each line other than the first. 823 | // Newlines are included in the output. 824 | // 825 | // Examples: 826 | // 827 | // optional int32 foo = 1; // Comment attached to foo. 828 | // // Comment attached to bar. 829 | // optional int32 bar = 2; 830 | // 831 | // optional string baz = 3; 832 | // // Comment attached to baz. 833 | // // Another line attached to baz. 834 | // 835 | // // Comment attached to qux. 836 | // // 837 | // // Another line attached to qux. 838 | // optional double qux = 4; 839 | // 840 | // // Detached comment for corge. This is not leading or trailing comments 841 | // // to qux or corge because there are blank lines separating it from 842 | // // both. 843 | // 844 | // // Detached comment for corge paragraph 2. 845 | // 846 | // optional string corge = 5; 847 | // /* Block comment attached 848 | // * to corge. Leading asterisks 849 | // * will be removed. */ 850 | // /* Block comment attached to 851 | // * grault. */ 852 | // optional int32 grault = 6; 853 | // 854 | // // ignored detached comments. 855 | optional string leading_comments = 3; 856 | optional string trailing_comments = 4; 857 | repeated string leading_detached_comments = 6; 858 | } 859 | } 860 | 861 | // Describes the relationship between generated code and its original source 862 | // file. A GeneratedCodeInfo message is associated with only one generated 863 | // source file, but may contain references to different source .proto files. 864 | message GeneratedCodeInfo { 865 | // An Annotation connects some span of text in generated code to an element 866 | // of its generating .proto file. 867 | repeated Annotation annotation = 1; 868 | message Annotation { 869 | // Identifies the element in the original source .proto file. This field 870 | // is formatted the same as SourceCodeInfo.Location.path. 871 | repeated int32 path = 1 [packed = true]; 872 | 873 | // Identifies the filesystem path to the original source .proto. 874 | optional string source_file = 2; 875 | 876 | // Identifies the starting offset in bytes in the generated code 877 | // that relates to the identified object. 878 | optional int32 begin = 3; 879 | 880 | // Identifies the ending offset in bytes in the generated code that 881 | // relates to the identified offset. The end offset should be one past 882 | // the last relevant byte (so the length of the text = end - begin). 883 | optional int32 end = 4; 884 | } 885 | } 886 | --------------------------------------------------------------------------------