ts-proto-client 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +87 -66
  2. package/dist/index.js +48 -87
  3. package/package.json +3 -2
package/README.md CHANGED
@@ -1,14 +1,14 @@
1
1
  # ts-proto-client
2
2
 
3
- 基于 Proto 文件自动生成 TypeScript 类型、请求接口及 Hooks CLI 工具。
3
+ 基于 Proto 文件自动生成 TypeScript 类型和 API 请求代码的 CLI 工具。
4
4
 
5
5
  ## 功能
6
6
 
7
- - 自动解析 Proto 文件
8
- - 生成 TypeScript 类型定义
9
- - 生成 API 请求方法
10
- - 生成 React Hooks(规划中)
11
- - 支持远程 Proto 仓库同步(规划中)
7
+ * 根据 `.proto` 文件生成 TypeScript 类型
8
+ * 根据 Service 定义生成 API 请求方法
9
+ * 支持自定义 Proto 根目录
10
+ * 支持自定义类型输出目录
11
+ * 支持自定义 API 输出目录
12
12
 
13
13
  ---
14
14
 
@@ -40,11 +40,11 @@ libprotoc 35.1
40
40
 
41
41
  ### Windows
42
42
 
43
- 1. 打开 Protocol Buffers Releases 页面:
43
+ 1. 打开 Protocol Buffers Releases 页面
44
44
 
45
45
  https://github.com/protocolbuffers/protobuf/releases
46
46
 
47
- 2. 下载对应版本:
47
+ 2. 下载对应版本
48
48
 
49
49
  ```text
50
50
  protoc-35.1-win64.zip
@@ -66,7 +66,7 @@ D:\protoc
66
66
  └─ readme.txt
67
67
  ```
68
68
 
69
- 4. 将以下目录添加到系统环境变量 `Path`:
69
+ 4. 将以下目录添加到系统环境变量:
70
70
 
71
71
  ```text
72
72
  D:\protoc\bin
@@ -88,109 +88,130 @@ libprotoc 35.1
88
88
 
89
89
  ## 使用方式
90
90
 
91
- ### 初始化配置
92
-
93
- 在项目根目录执行:
91
+ ### 生成代码
94
92
 
95
93
  ```bash
96
- npx proto-gen init
94
+ npx proto-gen generate \
95
+ --file ./account.proto \
96
+ --root ../protos \
97
+ --type-output src/protos/type \
98
+ --api-output src/protos/api/account
97
99
  ```
98
100
 
99
- 执行后会生成配置文件:
101
+ ### 参数说明
100
102
 
101
- ```text
102
- proto.config.json
103
- ```
103
+ | 参数 | 必填 | 说明 |
104
+ | --------------- | -- | ------------------------- |
105
+ | `--file` | 是 | Proto 文件路径(相对于 Proto 根目录) |
106
+ | `--root` | 是 | Proto 根目录 |
107
+ | `--type-output` | 是 | TypeScript 类型输出目录 |
108
+ | `--api-output` | 是 | API 文件输出目录 |
104
109
 
105
- 示例:
110
+ ---
106
111
 
107
- ```json
108
- {
109
- "ProtoRoot": "../protos",
110
- "ProtoInput": "hospital/hospital.proto",
111
- "ProtoTypeOutputPath": "./src/proto-type",
112
- "ApiOutputPath": "./src/api"
113
- }
114
- ```
112
+ ## 示例
115
113
 
116
- ---
114
+ 目录结构:
117
115
 
118
- ### 生成 TypeScript 类型和接口
116
+ ```text
117
+ project
118
+ ├─ src
119
+ ├─ protos
120
+ │ ├─ hospital
121
+ │ │ └─ account.proto
122
+ │ └─ third_party
123
+ └─ package.json
124
+ ```
125
+
126
+ 执行:
119
127
 
120
128
  ```bash
121
- npx proto-gen generate
129
+ npx proto-gen generate \
130
+ --file hospital/account.proto \
131
+ --root ./protos \
132
+ --type-output src/protos/type \
133
+ --api-output src/protos/api/account
122
134
  ```
123
135
 
124
- 执行后将根据配置自动生成:
136
+ 生成:
125
137
 
126
138
  ```text
127
139
  src
128
- ├─ proto-type
129
- │ └─ *.ts
130
- └─ api
131
- └─ *.ts
140
+ └─ protos
141
+ ├─ type
142
+ └─ account.ts
143
+ └─ api
144
+ └─ account.ts
132
145
  ```
133
146
 
134
147
  ---
135
148
 
136
- ## 配置说明
149
+ ## 本地开发
137
150
 
138
- | 字段 | 说明 |
139
- |--------|--------|
140
- | ProtoRoot | Proto 根目录 |
141
- | ProtoInput | 入口 Proto 文件 |
142
- | ProtoTypeOutputPath | TypeScript 类型输出目录 |
143
- | ApiOutputPath | API 文件输出目录 |
151
+ 启动开发模式:
144
152
 
145
- 示例:
153
+ ```bash
154
+ pnpm dev generate \
155
+ --file hospital/account.proto \
156
+ --root ../protos \
157
+ --type-output src/protos/type \
158
+ --api-output src/protos/api/account
159
+ ```
146
160
 
147
- ```json
148
- {
149
- "ProtoRoot": "../protos",
150
- "ProtoInput": "hospital/hospital.proto",
151
- "ProtoTypeOutputPath": "./src/proto-type",
152
- "ApiOutputPath": "./src/api"
153
- }
161
+ ---
162
+
163
+ ## 常见问题
164
+
165
+ ### protoc: command not found
166
+
167
+ 请确认已经正确安装 protoc,并配置到环境变量:
168
+
169
+ ```bash
170
+ protoc --version
154
171
  ```
155
172
 
173
+ 能够正常输出版本号。
174
+
156
175
  ---
157
176
 
158
- ## 命令
177
+ ### File does not reside within any path specified using --proto_path
159
178
 
160
- ### 初始化配置
179
+ 请检查:
161
180
 
162
181
  ```bash
163
- npx proto-gen init
182
+ --file
164
183
  ```
165
184
 
166
- ### 生成代码
185
+ 指定的文件是否位于:
167
186
 
168
187
  ```bash
169
- npx proto-gen generate
188
+ --root
170
189
  ```
171
190
 
172
- ---
191
+ 指定的目录之下。
192
+
193
+ 例如:
194
+
195
+ ```bash
196
+ --root ./protos
197
+ --file hospital/account.proto
198
+ ```
173
199
 
174
- ## 目录示例
200
+ 则实际文件应存在:
175
201
 
176
202
  ```text
177
- project
178
- ├─ proto.config.json
179
- ├─ src
180
- │ ├─ api
181
- │ └─ proto-type
182
- └─ protos
203
+ ./protos/hospital/account.proto
183
204
  ```
184
205
 
185
206
  ---
186
207
 
187
- ## 版本要求
208
+ ## 环境要求
188
209
 
189
- - Node.js >= 18
190
- - Protocol Buffers (protoc) >= 35
210
+ * Node.js >= 18
211
+ * protoc >= 35
191
212
 
192
213
  ---
193
214
 
194
215
  ## License
195
216
 
196
- MIT
217
+ MIT
package/dist/index.js CHANGED
@@ -3,67 +3,18 @@
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
5
 
6
- // src/commands/init.ts
7
- import prompts from "prompts";
8
- import fs from "fs";
9
- var ConfigFilePath = "proto.config.json";
10
- async function init() {
11
- const answers = await prompts([
12
- {
13
- type: "text",
14
- name: "ProtoRoot",
15
- message: "proto \u8F93\u5165\u6587\u4EF6",
16
- initial: "../protos"
17
- },
18
- {
19
- type: "text",
20
- name: "ProtoInputPath",
21
- message: "proto \u8F93\u5165\u6587\u4EF6",
22
- initial: "hospital/hospital.proto"
23
- },
24
- {
25
- type: "text",
26
- name: "ProtoTypeOutputPath",
27
- message: "\u7C7B\u578B\u8F93\u51FA\u8DEF\u5F84",
28
- initial: "dist/proto-type"
29
- },
30
- {
31
- type: "text",
32
- name: "ProtoApiOutputPath",
33
- message: "\u63A5\u53E3\u8F93\u51FA\u8DEF\u5F84",
34
- initial: "dist/proto-api"
35
- },
36
- {
37
- type: "text",
38
- name: "ImportTypePath",
39
- message: "\u7C7B\u578B\u6587\u4EF6\u5BFC\u5165\u63A5\u53E3\u7684\u8DEF\u5F84",
40
- initial: "../proto-type/hospital/hospital"
41
- }
42
- ]);
43
- const content = [
44
- "{",
45
- ` "ProtoRoot": "${answers.ProtoRoot}",`,
46
- ` "ProtoInput": "${answers.ProtoInputPath}",`,
47
- ` "ProtoTypeOutputPath": "${answers.ProtoTypeOutputPath}",`,
48
- ` "ProtoApiOutputPath": "${answers.ProtoApiOutputPath}",`,
49
- ` "ImportTypePath": "${answers.ImportTypePath}"`,
50
- "}"
51
- ].join("\n");
52
- fs.writeFileSync(ConfigFilePath, content);
53
- }
54
-
55
6
  // src/commands/generate.ts
56
- import fs5 from "fs";
7
+ import fs4 from "fs";
57
8
  import path4 from "path";
58
9
 
59
10
  // src/generators/api.ts
60
- import fs3 from "fs";
11
+ import fs2 from "fs";
61
12
  import path2 from "path";
62
13
 
63
14
  // src/utils/index.ts
64
15
  import { Root, Service } from "protobufjs";
65
16
  import path from "path";
66
- import fs2 from "fs";
17
+ import fs from "fs";
67
18
 
68
19
  // src/constants.ts
69
20
  var HTTP_METHODS = [
@@ -87,7 +38,7 @@ function createRoot(rootPath) {
87
38
  includePath,
88
39
  target
89
40
  );
90
- if (fs2.existsSync(filePath)) {
41
+ if (fs.existsSync(filePath)) {
91
42
  return filePath;
92
43
  }
93
44
  }
@@ -181,19 +132,24 @@ function generateApiCode(apis, importTypePath) {
181
132
  }
182
133
  return modules;
183
134
  }
135
+ function getOutputPath(baseDir, protoFile) {
136
+ const normalized = protoFile.replace(/\\/g, "/").replace(/^\.?\//, "").replace(/\.proto$/, "");
137
+ return path.join(baseDir, normalized);
138
+ }
184
139
 
185
140
  // src/generators/api.ts
186
- function generateApi() {
187
- const config = JSON.parse(fs3.readFileSync("proto.config.json", "utf8"));
188
- const outputPath = path2.resolve(process.cwd(), config.ProtoApiOutputPath);
189
- if (!fs3.existsSync(outputPath)) {
190
- fs3.mkdirSync(outputPath, { recursive: true });
141
+ function generateApi(options) {
142
+ const outputPath = path2.resolve(process.cwd(), options.apiOutput);
143
+ if (!fs2.existsSync(outputPath)) {
144
+ fs2.mkdirSync(outputPath, { recursive: true });
191
145
  }
192
- const apis = parseProto(config.ProtoRoot, config.ProtoInput);
193
- const codes = generateApiCode(apis, config.ImportTypePath);
146
+ const apis = parseProto(options.root, options.file);
147
+ const result = getOutputPath(options.typeOutput, options.file);
148
+ const relativePath = path2.relative(options.apiOutput, result).replace(/\\/g, "/");
149
+ const codes = generateApiCode(apis, relativePath);
194
150
  for (const code of codes) {
195
151
  for (const [name, content] of Object.entries(code)) {
196
- fs3.writeFileSync(`${outputPath}/${name}.ts`, content, "utf8");
152
+ fs2.writeFileSync(`${outputPath}/${name}.ts`, content, "utf8");
197
153
  }
198
154
  }
199
155
  console.log("\u2705 Generate Success");
@@ -202,20 +158,19 @@ function generateApi() {
202
158
  // src/generators/type.ts
203
159
  import { execSync } from "child_process";
204
160
  import { createRequire } from "module";
205
- import fs4 from "fs";
161
+ import fs3 from "fs";
206
162
  import path3 from "path";
207
- function generateTypes() {
163
+ function generateTypes(options) {
208
164
  const require2 = createRequire(import.meta.url);
209
165
  const tsProtoPkg = require2.resolve("ts-proto/package.json");
210
166
  const tsProtoRoot = path3.dirname(tsProtoPkg);
211
167
  const pluginName = process.platform === "win32" ? "protoc-gen-ts_proto.cmd" : "protoc-gen-ts_proto";
212
168
  const pluginPath = path3.resolve(tsProtoRoot, `./node_modules/.bin/${pluginName}`);
213
- const config = JSON.parse(fs4.readFileSync("proto.config.json", "utf8"));
214
- const outputPath = path3.resolve(process.cwd(), config.ProtoTypeOutputPath);
215
- if (!fs4.existsSync(outputPath)) {
216
- fs4.mkdirSync(outputPath, { recursive: true });
169
+ const outputPath = path3.resolve(process.cwd(), options.typeOutput);
170
+ if (!fs3.existsSync(outputPath)) {
171
+ fs3.mkdirSync(outputPath, { recursive: true });
217
172
  }
218
- const rootPath = path3.resolve(process.cwd(), config.ProtoRoot);
173
+ const rootPath = path3.resolve(process.cwd(), options.root);
219
174
  const configs = [
220
175
  "protoc",
221
176
  `--plugin=protoc-gen-ts_proto=${pluginPath}`,
@@ -226,44 +181,50 @@ function generateTypes() {
226
181
  // message 字段生成可选属性
227
182
  "--ts_proto_opt=esModuleInterop=true",
228
183
  // 使用 ES Module 风格导入
229
- "--ts_proto_opt=comments=false",
230
- // 去掉注释
231
184
  `--proto_path=${rootPath}`,
232
185
  `--proto_path=${path3.join(rootPath, "/third_party/googleapis")}`,
233
186
  // protos 中的 google 依赖
234
- path3.join(rootPath, config.ProtoInput)
187
+ path3.join(rootPath, options.file)
235
188
  ];
236
189
  execSync(configs.join(" "), { stdio: "inherit" });
237
- fs4.rmSync(
190
+ fs3.rmSync(
238
191
  path3.join(outputPath, "google"),
239
192
  { recursive: true, force: true }
240
193
  );
241
- fs4.rmSync(
194
+ fs3.rmSync(
242
195
  path3.join(outputPath, "common.ts"),
243
196
  { force: true }
244
197
  );
245
198
  }
246
199
 
247
200
  // src/commands/generate.ts
248
- async function generate() {
249
- if (!fs5.existsSync("proto.config.json")) {
250
- console.log("\u8BF7\u521D\u59CB\u5316\u914D\u7F6E");
251
- return;
252
- }
253
- const config = JSON.parse(
254
- fs5.readFileSync("proto.config.json", "utf8")
255
- );
256
- if (!fs5.existsSync(path4.resolve(process.cwd(), config.ProtoRoot))) {
257
- console.log(`proto \u9879\u76EE\u4E0D\u5B58\u5728(${config.ProtoRoot})`);
201
+ async function generate(options) {
202
+ if (!fs4.existsSync(path4.resolve(process.cwd(), options.root))) {
203
+ console.log(`proto \u9879\u76EE\u4E0D\u5B58\u5728(${options.root})`);
258
204
  return;
259
205
  }
260
- generateTypes();
261
- generateApi();
206
+ generateTypes(options);
207
+ generateApi(options);
262
208
  }
263
209
 
264
210
  // src/index.ts
265
211
  var program = new Command();
266
212
  program.name("proto-gen").description("proto code generator").version("1.0.0");
267
- program.command("init").action(init);
268
- program.command("generate").action(generate);
213
+ program.command("generate").option("--file, --file <path>").option("--root, --root <path>").option("--type-output, --typeOutput <path>").option("--api-output, --apiOutput <path>").action((options) => {
214
+ if (options.file === void 0) {
215
+ console.log("proto file \u4E0D\u80FD\u4E3A\u7A7A, \u8BF7\u8F93\u5165 --file ./account.proto");
216
+ return;
217
+ }
218
+ if (options.root === void 0) {
219
+ console.log("proto \u6587\u4EF6\u7684\u6839\u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A, \u8BF7\u8F93\u5165 --root ../protos");
220
+ return;
221
+ }
222
+ if (options.typeOutput === void 0) {
223
+ options.typeOutput = "src/protos/type";
224
+ }
225
+ if (options.apiOutput === void 0) {
226
+ options.apiOutput = "src/protos/api";
227
+ }
228
+ generate(options);
229
+ });
269
230
  program.parse();
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "ts-proto-client",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "type": "module",
5
5
  "description": "",
6
6
  "scripts": {
7
7
  "dev": "tsx src/index.ts",
8
- "build": "tsup src/index.ts --format esm --clean"
8
+ "build": "tsup src/index.ts --format esm --clean",
9
+ "release": "pnpm build && npm publish"
9
10
  },
10
11
  "bin": {
11
12
  "proto-gen": "./dist/index.js"