protobuf-fastdsl 0.1.3 → 0.1.5

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 +64 -20
  2. package/dist/index.js +5 -11
  3. package/package.json +9 -9
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # protobuf-fastdsl
2
2
 
3
- 一个 Vite 插件,将 TypeScript protobuf 接口在构建时编译为**完全内联**、零依赖的编解码函数。
3
+ TypeScript 接口在构建时编译为**完全内联**、零依赖的 protobuf 编解码函数。
4
4
 
5
5
  无 `.proto` 文件。无运行时库。无函数调用开销。只需 TypeScript 接口 → 确定化的二进制编解码代码。
6
6
 
@@ -8,9 +8,11 @@
8
8
 
9
9
  - **零运行时** — 所有 wire-format 逻辑在编译时内联
10
10
  - **TypeScript 原生** — 用 `pb<N, Type>` 标记接口字段即可定义 schema
11
+ - **跨文件类型** — 支持 `import type` / `import` 引用其他文件的接口定义
11
12
  - **泛型单态化** — `Wrapper<Wrapper<string>>` → 自动生成具体编解码函数
12
13
  - **重复字段** — `pb_repeated<N, Type>` 编译为 `Type[]`
13
14
  - **编译期预计算 Tag** — 字段标签在编译时折叠为字面量字节
15
+ - **安全的 Fallback** — 未经插件转换时运行会直接抛错,不会静默产生错误结果
14
16
 
15
17
  ## 安装
16
18
 
@@ -20,30 +22,24 @@ npm install protobuf-fastdsl
20
22
 
21
23
  ## 快速开始
22
24
 
23
- **1. 在 `vite.config.ts` 中添加插件:**
25
+ **1. 配置构建工具插件:**
24
26
 
25
27
  ```ts
26
- import protobufVite from 'protobuf-fastdsl';
28
+ // vite.config.ts
29
+ import protobufPlugin from 'protobuf-fastdsl/vite';
27
30
 
28
31
  export default defineConfig({
29
- plugins: [protobufVite()],
32
+ plugins: [protobufPlugin()],
30
33
  });
31
34
  ```
32
35
 
33
- **2. `tsconfig.json` 中添加类型声明:**
34
-
35
- ```json
36
- {
37
- "compilerOptions": {
38
- "types": ["protobuf-fastdsl/types"]
39
- }
40
- }
41
- ```
42
-
43
- **3. 用 TypeScript 接口定义 schema:**
36
+ **2. 定义 protobuf schema(TypeScript 接口):**
44
37
 
45
38
  ```ts
46
- interface UserProfile {
39
+ // schema/user.ts
40
+ import type { pb, pb_repeated, uint_32, bool } from 'protobuf-fastdsl';
41
+
42
+ export interface UserProfile {
47
43
  id: pb<1, uint_32>;
48
44
  username: pb<2, string>;
49
45
  active: pb<3, bool>;
@@ -51,9 +47,12 @@ interface UserProfile {
51
47
  }
52
48
  ```
53
49
 
54
- **4. 使用 `protobuf_encode` / `protobuf_decode`:**
50
+ **3. 编解码:**
55
51
 
56
52
  ```ts
53
+ import { protobuf_encode, protobuf_decode } from 'protobuf-fastdsl';
54
+ import type { UserProfile } from './schema/user';
55
+
57
56
  const bytes = protobuf_encode<UserProfile>({
58
57
  id: 42,
59
58
  username: 'alice',
@@ -65,7 +64,7 @@ const user = protobuf_decode<UserProfile>(bytes);
65
64
  // user.id === 42, user.tags === ['admin', 'dev']
66
65
  ```
67
66
 
68
- 构建时,插件会将上述代码转换为:
67
+ 构建时,插件将上述代码转换为:
69
68
 
70
69
  ```js
71
70
  // 预计算的 tag 字面量,内联 varint 循环,零函数调用
@@ -73,6 +72,43 @@ const bytes = protobuf_encode_UserProfile({ id: 42, ... });
73
72
  const user = protobuf_decode_UserProfile(bytes);
74
73
  ```
75
74
 
75
+ 如果忘记配置插件,`protobuf_encode` / `protobuf_decode` 会在运行时抛出错误提示。
76
+
77
+ ## 跨文件类型引用
78
+
79
+ 接口定义和编解码调用可以在不同文件中,插件会自动跟踪 import 链:
80
+
81
+ ```ts
82
+ // inner.ts
83
+ import type { pb, uint_32 } from 'protobuf-fastdsl';
84
+
85
+ export interface Inner {
86
+ value: pb<1, uint_32>;
87
+ }
88
+
89
+ // outer.ts
90
+ import { protobuf_encode } from 'protobuf-fastdsl';
91
+ import type { Inner } from './inner';
92
+ import type { pb } from 'protobuf-fastdsl';
93
+
94
+ interface Outer {
95
+ inner: pb<1, Inner>;
96
+ }
97
+
98
+ const bytes = protobuf_encode<Outer>({ inner: { value: 42 } });
99
+ ```
100
+
101
+ 支持传递性导入(A → B → C),插件会递归解析所有依赖。
102
+
103
+ ## 别名导入
104
+
105
+ ```ts
106
+ import { protobuf_encode as encode, protobuf_decode as decode } from 'protobuf-fastdsl';
107
+
108
+ const bytes = encode<UserProfile>(data); // → protobuf_encode_UserProfile(data)
109
+ const user = decode<UserProfile>(bytes); // → protobuf_decode_UserProfile(bytes)
110
+ ```
111
+
76
112
  ## 泛型单态化
77
113
 
78
114
  定义泛型 protobuf 模板,使用具体类型实例化:
@@ -95,8 +131,8 @@ const data = protobuf_encode<Wrapper<Wrapper<string>>>({
95
131
  |---------------|-----------------|-----------|
96
132
  | `uint_32`, `int_32` | `number` | Varint |
97
133
  | `uint_64`, `int_64` | `bigint` | Varint |
98
- | `sint_32` | `number` | Varint |
99
- | `sint_64` | `bigint` | Varint |
134
+ | `sint_32` | `number` | Varint (ZigZag) |
135
+ | `sint_64` | `bigint` | Varint (ZigZag) |
100
136
  | `bool` | `boolean` | Varint |
101
137
  | `string` | `string` | LengthDelimited |
102
138
  | `bytes` | `Uint8Array` | LengthDelimited |
@@ -111,6 +147,14 @@ const data = protobuf_encode<Wrapper<Wrapper<string>>>({
111
147
 
112
148
  说明:
113
149
  - 所有 64 位整数类型在 TypeScript 中统一映射为 `bigint`
150
+ - `sint_32` / `sint_64` 使用 ZigZag 编码,适用于频繁出现负数的场景
151
+
152
+ ## 包入口
153
+
154
+ | 路径 | 用途 |
155
+ |------|------|
156
+ | `protobuf-fastdsl` | 用户代码 — `protobuf_encode`、`protobuf_decode`、所有类型 |
157
+ | `protobuf-fastdsl/vite` | Vite 插件 |
114
158
 
115
159
  ## ⚡ 性能测试
116
160
 
package/dist/index.js CHANGED
@@ -1167,7 +1167,7 @@ function replaceCallSites(code, registry) {
1167
1167
  import ts6 from "typescript";
1168
1168
  import { readFileSync, existsSync } from "fs";
1169
1169
  import { dirname, resolve } from "path";
1170
- function extractTypeImports(sf) {
1170
+ function extractImports(sf) {
1171
1171
  const result = [];
1172
1172
  for (const stmt of sf.statements) {
1173
1173
  if (!ts6.isImportDeclaration(stmt) || !stmt.importClause) continue;
@@ -1176,15 +1176,9 @@ function extractTypeImports(sf) {
1176
1176
  const specifier = spec.text;
1177
1177
  const clause = stmt.importClause;
1178
1178
  const names = [];
1179
- if (clause.isTypeOnly) {
1180
- if (clause.namedBindings && ts6.isNamedImports(clause.namedBindings)) {
1181
- for (const el of clause.namedBindings.elements) {
1182
- names.push(el.name.text);
1183
- }
1184
- }
1185
- } else if (clause.namedBindings && ts6.isNamedImports(clause.namedBindings)) {
1179
+ if (clause.namedBindings && ts6.isNamedImports(clause.namedBindings)) {
1186
1180
  for (const el of clause.namedBindings.elements) {
1187
- if (el.isTypeOnly) names.push(el.name.text);
1181
+ names.push(el.name.text);
1188
1182
  }
1189
1183
  }
1190
1184
  if (names.length > 0) result.push({ names, specifier });
@@ -1229,7 +1223,7 @@ function resolveImports(code, importerPath, cache) {
1229
1223
  visiting.add(abs);
1230
1224
  const src = fileCode ?? readFileSync(abs, "utf-8");
1231
1225
  const sf = ts6.createSourceFile(abs, src, ts6.ScriptTarget.Latest, true);
1232
- const imports = extractTypeImports(sf);
1226
+ const imports = extractImports(sf);
1233
1227
  for (const imp of imports) {
1234
1228
  const resolved = resolveModulePath(imp.specifier, abs);
1235
1229
  if (!resolved) continue;
@@ -1263,7 +1257,7 @@ function protobufVitePlugin() {
1263
1257
  if (!id.endsWith(".ts") || id.endsWith(".d.ts")) return null;
1264
1258
  const imported = resolveImports(code, id, fileCache);
1265
1259
  const { registry, callSites, sourceFile } = analyze(code, id, imported);
1266
- if (registry.size === 0) return null;
1260
+ if (registry.size === 0 && callSites.length === 0) return null;
1267
1261
  const generatedCode = generateCode(registry);
1268
1262
  const { transformedCode, hasReplacements } = applyReplacements(code, sourceFile, callSites, registry);
1269
1263
  if (!hasReplacements && generatedCode === "") return null;
package/package.json CHANGED
@@ -1,24 +1,21 @@
1
1
  {
2
2
  "name": "protobuf-fastdsl",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
5
+ "main": "dist/runtime.js",
6
+ "types": "protobuf.d.ts",
7
7
  "files": [
8
8
  "dist",
9
9
  "protobuf.d.ts"
10
10
  ],
11
11
  "exports": {
12
12
  ".": {
13
- "types": "./dist/index.d.ts",
14
- "import": "./dist/index.js"
15
- },
16
- "./runtime": {
17
13
  "types": "./protobuf.d.ts",
18
14
  "import": "./dist/runtime.js"
19
15
  },
20
- "./types": {
21
- "types": "./protobuf.d.ts"
16
+ "./vite": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js"
22
19
  }
23
20
  },
24
21
  "scripts": {
@@ -33,6 +30,9 @@
33
30
  "peerDependencies": {
34
31
  "vite": "^5.0.0 || ^6.0.0 || ^7.0.0"
35
32
  },
33
+ "peerDependenciesMeta": {
34
+ "vite": { "optional": true }
35
+ },
36
36
  "devDependencies": {
37
37
  "@types/node": "^25.4.0",
38
38
  "tsup": "^8.0.0",