@naeemo/capnp 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +103 -0
- package/README.zh.md +83 -0
- package/dist/cli.js +394 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +765 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +747 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 capnp-ts contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Cap'n Proto TypeScript
|
|
2
|
+
|
|
3
|
+
A pure TypeScript implementation of Cap'n Proto, featuring zero-copy deserialization and full interoperability with the official C++ implementation.
|
|
4
|
+
|
|
5
|
+
[中文文档](./README.zh.md)
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- 🚀 **Zero-Copy Deserialization** - Read data directly from buffers without parsing
|
|
10
|
+
- 🔧 **Pure TypeScript** - No WASM or native dependencies, works in any JS environment
|
|
11
|
+
- ✅ **Official Compatible** - Tested against official C++ implementation
|
|
12
|
+
- 📦 **Schema Code Generation** - Generate TypeScript types from `.capnp` schemas
|
|
13
|
+
- ⚡ **High Performance** - 1.4μs serialization, 0.6μs deserialization for simple structs
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @naeemo/capnp
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
### Basic Usage
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { MessageBuilder, MessageReader } from '@naeemo/capnp';
|
|
27
|
+
|
|
28
|
+
// Build a message
|
|
29
|
+
const builder = new MessageBuilder();
|
|
30
|
+
const root = builder.initRoot(2, 1); // 2 data words, 1 pointer
|
|
31
|
+
root.setInt32(0, 42);
|
|
32
|
+
root.setText(0, 'Hello, Cap\'n Proto!');
|
|
33
|
+
const buffer = builder.toArrayBuffer();
|
|
34
|
+
|
|
35
|
+
// Read a message
|
|
36
|
+
const reader = new MessageReader(buffer);
|
|
37
|
+
const data = reader.getRoot(2, 1);
|
|
38
|
+
console.log(data.getInt32(0)); // 42
|
|
39
|
+
console.log(data.getText(0)); // "Hello, Cap'n Proto!"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Code Generation
|
|
43
|
+
|
|
44
|
+
Generate TypeScript types from your Cap'n Proto schema:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npx tsx src/cli/codegen.ts schema.capnp -o types.ts
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Generated code includes:
|
|
51
|
+
- TypeScript interfaces
|
|
52
|
+
- Reader classes (getters)
|
|
53
|
+
- Builder classes (setters + factory method)
|
|
54
|
+
|
|
55
|
+
Example:
|
|
56
|
+
```typescript
|
|
57
|
+
// Generated from schema
|
|
58
|
+
export interface Person {
|
|
59
|
+
id: bigint;
|
|
60
|
+
name: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export class PersonReader {
|
|
64
|
+
get id(): bigint { ... }
|
|
65
|
+
get name(): string { ... }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export class PersonBuilder {
|
|
69
|
+
static create(message: MessageBuilder): PersonBuilder { ... }
|
|
70
|
+
setId(value: bigint): void { ... }
|
|
71
|
+
setName(value: string): void { ... }
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Performance
|
|
76
|
+
|
|
77
|
+
| Operation | Latency | Throughput |
|
|
78
|
+
|-----------|---------|------------|
|
|
79
|
+
| Simple struct serialize | 1.4 μs | 684K ops/sec |
|
|
80
|
+
| Simple struct deserialize | 0.6 μs | 1.66M ops/sec |
|
|
81
|
+
| Nested struct serialize | 4.1 μs | 243K ops/sec |
|
|
82
|
+
| List (100 items) serialize | 6.8 μs | 147K ops/sec |
|
|
83
|
+
|
|
84
|
+
See [PERFORMANCE.md](./PERFORMANCE.md) for detailed benchmarks.
|
|
85
|
+
|
|
86
|
+
## Documentation
|
|
87
|
+
|
|
88
|
+
- [API Documentation](./docs/API.md)
|
|
89
|
+
- [Performance Report](./PERFORMANCE.md)
|
|
90
|
+
- [Test Coverage](./TEST_COVERAGE.md)
|
|
91
|
+
- [Changelog](./CHANGELOG.md)
|
|
92
|
+
|
|
93
|
+
## Contributing
|
|
94
|
+
|
|
95
|
+
We welcome contributions! Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines.
|
|
96
|
+
|
|
97
|
+
## Credits
|
|
98
|
+
|
|
99
|
+
Developed by **Naeemo** and [Moonshot AI](https://github.com/MoonshotAI).
|
|
100
|
+
|
|
101
|
+
## License
|
|
102
|
+
|
|
103
|
+
MIT License - see [LICENSE](./LICENSE) for details.
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Cap'n Proto TypeScript
|
|
2
|
+
|
|
3
|
+
纯 TypeScript 实现的 Cap'n Proto,支持零拷贝反序列化,与官方 C++ 实现完全兼容。
|
|
4
|
+
|
|
5
|
+
[English Documentation](./README.md)
|
|
6
|
+
|
|
7
|
+
## 特性
|
|
8
|
+
|
|
9
|
+
- 🚀 **零拷贝反序列化** - 直接从缓冲区读取数据,无需解析
|
|
10
|
+
- 🔧 **纯 TypeScript** - 无 WASM 或原生依赖,可在任何 JS 环境运行
|
|
11
|
+
- ✅ **官方兼容** - 已通过官方 C++ 实现测试验证
|
|
12
|
+
- 📦 **Schema 代码生成** - 从 `.capnp` 模式生成 TypeScript 类型
|
|
13
|
+
- ⚡ **高性能** - 简单结构序列化 1.4μs,反序列化 0.6μs
|
|
14
|
+
|
|
15
|
+
## 安装
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @naeemo/capnp
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 快速开始
|
|
22
|
+
|
|
23
|
+
### 基础用法
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { MessageBuilder, MessageReader } from '@naeemo/capnp';
|
|
27
|
+
|
|
28
|
+
// 构建消息
|
|
29
|
+
const builder = new MessageBuilder();
|
|
30
|
+
const root = builder.initRoot(2, 1); // 2 个数据字,1 个指针
|
|
31
|
+
root.setInt32(0, 42);
|
|
32
|
+
root.setText(0, '你好,Cap\'n Proto!');
|
|
33
|
+
const buffer = builder.toArrayBuffer();
|
|
34
|
+
|
|
35
|
+
// 读取消息
|
|
36
|
+
const reader = new MessageReader(buffer);
|
|
37
|
+
const data = reader.getRoot(2, 1);
|
|
38
|
+
console.log(data.getInt32(0)); // 42
|
|
39
|
+
console.log(data.getText(0)); // "你好,Cap'n Proto!"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 代码生成
|
|
43
|
+
|
|
44
|
+
从 Cap'n Proto 模式生成 TypeScript 类型:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npx tsx src/cli/codegen.ts schema.capnp -o types.ts
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
生成的代码包括:
|
|
51
|
+
- TypeScript 接口
|
|
52
|
+
- Reader 类(getter)
|
|
53
|
+
- Builder 类(setter + 工厂方法)
|
|
54
|
+
|
|
55
|
+
## 性能
|
|
56
|
+
|
|
57
|
+
| 操作 | 延迟 | 吞吐量 |
|
|
58
|
+
|-----------|---------|------------|
|
|
59
|
+
| 简单结构序列化 | 1.4 μs | 68万 ops/sec |
|
|
60
|
+
| 简单结构反序列化 | 0.6 μs | 166万 ops/sec |
|
|
61
|
+
| 嵌套结构序列化 | 4.1 μs | 24万 ops/sec |
|
|
62
|
+
| 列表(100项)序列化 | 6.8 μs | 14万 ops/sec |
|
|
63
|
+
|
|
64
|
+
详见 [PERFORMANCE.md](./PERFORMANCE.md)
|
|
65
|
+
|
|
66
|
+
## 文档
|
|
67
|
+
|
|
68
|
+
- [API 文档](./docs/API.md)
|
|
69
|
+
- [性能报告](./PERFORMANCE.md)
|
|
70
|
+
- [测试覆盖](./TEST_COVERAGE.md)
|
|
71
|
+
- [更新日志](./CHANGELOG.md)
|
|
72
|
+
|
|
73
|
+
## 贡献
|
|
74
|
+
|
|
75
|
+
欢迎贡献!请查看 [CONTRIBUTING.md](./CONTRIBUTING.md) 了解指南。
|
|
76
|
+
|
|
77
|
+
## 致谢
|
|
78
|
+
|
|
79
|
+
由 **Naeemo** 和 [Moonshot AI](https://github.com/MoonshotAI) 共同开发。
|
|
80
|
+
|
|
81
|
+
## 许可证
|
|
82
|
+
|
|
83
|
+
MIT 许可证 - 详见 [LICENSE](./LICENSE)
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
#!/usr/bin/env node
|
|
3
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { parseArgs } from "node:util";
|
|
5
|
+
|
|
6
|
+
//#region src/codegen/enum-gen.ts
|
|
7
|
+
/**
|
|
8
|
+
* Enum generator
|
|
9
|
+
*/
|
|
10
|
+
function generateEnum(enum_, lines) {
|
|
11
|
+
lines.push(`export enum ${enum_.name} {`);
|
|
12
|
+
for (const value of enum_.values) lines.push(` ${value.name} = ${value.index},`);
|
|
13
|
+
lines.push("}");
|
|
14
|
+
lines.push("");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/codegen/type-utils.ts
|
|
19
|
+
function isPointerType(type) {
|
|
20
|
+
if (typeof type === "string") return type === "Text" || type === "Data";
|
|
21
|
+
return type.kind === "list" || type.kind === "struct";
|
|
22
|
+
}
|
|
23
|
+
function getTypeSize(type) {
|
|
24
|
+
if (typeof type !== "string") return 8;
|
|
25
|
+
switch (type) {
|
|
26
|
+
case "Void": return 0;
|
|
27
|
+
case "Bool": return 1;
|
|
28
|
+
case "Int8":
|
|
29
|
+
case "UInt8": return 1;
|
|
30
|
+
case "Int16":
|
|
31
|
+
case "UInt16": return 2;
|
|
32
|
+
case "Int32":
|
|
33
|
+
case "UInt32":
|
|
34
|
+
case "Float32": return 4;
|
|
35
|
+
case "Int64":
|
|
36
|
+
case "UInt64":
|
|
37
|
+
case "Float64": return 8;
|
|
38
|
+
default: return 8;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function mapTypeToTs(type) {
|
|
42
|
+
if (typeof type !== "string") {
|
|
43
|
+
if (type.kind === "list") return `${mapTypeToTs(type.elementType)}[]`;
|
|
44
|
+
return type.name;
|
|
45
|
+
}
|
|
46
|
+
switch (type) {
|
|
47
|
+
case "Void": return "void";
|
|
48
|
+
case "Bool": return "boolean";
|
|
49
|
+
case "Int8":
|
|
50
|
+
case "Int16":
|
|
51
|
+
case "Int32":
|
|
52
|
+
case "UInt8":
|
|
53
|
+
case "UInt16":
|
|
54
|
+
case "UInt32":
|
|
55
|
+
case "Float32":
|
|
56
|
+
case "Float64": return "number";
|
|
57
|
+
case "Int64":
|
|
58
|
+
case "UInt64": return "bigint";
|
|
59
|
+
case "Text": return "string";
|
|
60
|
+
case "Data": return "Uint8Array";
|
|
61
|
+
default: return "unknown";
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function getGetterMethod(type) {
|
|
65
|
+
if (typeof type !== "string") {
|
|
66
|
+
if (type.kind === "list") return "getList";
|
|
67
|
+
return "getStruct";
|
|
68
|
+
}
|
|
69
|
+
switch (type) {
|
|
70
|
+
case "Void": return "getVoid";
|
|
71
|
+
case "Bool": return "getBool";
|
|
72
|
+
case "Int8": return "getInt8";
|
|
73
|
+
case "Int16": return "getInt16";
|
|
74
|
+
case "Int32": return "getInt32";
|
|
75
|
+
case "Int64": return "getInt64";
|
|
76
|
+
case "UInt8": return "getUint8";
|
|
77
|
+
case "UInt16": return "getUint16";
|
|
78
|
+
case "UInt32": return "getUint32";
|
|
79
|
+
case "UInt64": return "getUint64";
|
|
80
|
+
case "Float32": return "getFloat32";
|
|
81
|
+
case "Float64": return "getFloat64";
|
|
82
|
+
case "Text": return "getText";
|
|
83
|
+
case "Data": return "getData";
|
|
84
|
+
default: return "getUnknown";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function getSetterMethod(type) {
|
|
88
|
+
if (typeof type !== "string") {
|
|
89
|
+
if (type.kind === "list") return "initList";
|
|
90
|
+
return "initStruct";
|
|
91
|
+
}
|
|
92
|
+
switch (type) {
|
|
93
|
+
case "Void": return "setVoid";
|
|
94
|
+
case "Bool": return "setBool";
|
|
95
|
+
case "Int8": return "setInt8";
|
|
96
|
+
case "Int16": return "setInt16";
|
|
97
|
+
case "Int32": return "setInt32";
|
|
98
|
+
case "Int64": return "setInt64";
|
|
99
|
+
case "UInt8": return "setUint8";
|
|
100
|
+
case "UInt16": return "setUint16";
|
|
101
|
+
case "UInt32": return "setUint32";
|
|
102
|
+
case "UInt64": return "setUint64";
|
|
103
|
+
case "Float32": return "setFloat32";
|
|
104
|
+
case "Float64": return "setFloat64";
|
|
105
|
+
case "Text": return "setText";
|
|
106
|
+
case "Data": return "setData";
|
|
107
|
+
default: return "setUnknown";
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function capitalize(str) {
|
|
111
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region src/codegen/struct-gen.ts
|
|
116
|
+
function generateStruct(struct, lines) {
|
|
117
|
+
let dataWords = 0;
|
|
118
|
+
let pointerCount = 0;
|
|
119
|
+
let dataOffset = 0;
|
|
120
|
+
for (const field of struct.fields) if (isPointerType(field.type)) pointerCount++;
|
|
121
|
+
else dataOffset += getTypeSize(field.type);
|
|
122
|
+
dataWords = Math.ceil(dataOffset / 8);
|
|
123
|
+
lines.push(`export interface ${struct.name} {`);
|
|
124
|
+
for (const field of struct.fields) lines.push(` ${field.name}: ${mapTypeToTs(field.type)};`);
|
|
125
|
+
lines.push("}");
|
|
126
|
+
lines.push("");
|
|
127
|
+
generateReader(struct, dataWords, pointerCount, lines);
|
|
128
|
+
generateBuilder(struct, dataWords, pointerCount, lines);
|
|
129
|
+
}
|
|
130
|
+
function generateReader(struct, _dataWords, _pointerCount, lines) {
|
|
131
|
+
lines.push(`export class ${struct.name}Reader {`);
|
|
132
|
+
lines.push(" private reader: StructReader;");
|
|
133
|
+
lines.push("");
|
|
134
|
+
lines.push(" constructor(reader: StructReader) {");
|
|
135
|
+
lines.push(" this.reader = reader;");
|
|
136
|
+
lines.push(" }");
|
|
137
|
+
lines.push("");
|
|
138
|
+
let dataOffset = 0;
|
|
139
|
+
let pointerIndex = 0;
|
|
140
|
+
for (const field of struct.fields) {
|
|
141
|
+
const tsType = mapTypeToTs(field.type);
|
|
142
|
+
if (isPointerType(field.type)) {
|
|
143
|
+
lines.push(` get ${field.name}(): ${tsType} {`);
|
|
144
|
+
lines.push(` return this.reader.${getGetterMethod(field.type)}(${pointerIndex});`);
|
|
145
|
+
lines.push(" }");
|
|
146
|
+
pointerIndex++;
|
|
147
|
+
} else {
|
|
148
|
+
lines.push(` get ${field.name}(): ${tsType} {`);
|
|
149
|
+
lines.push(` return this.reader.${getGetterMethod(field.type)}(${dataOffset});`);
|
|
150
|
+
lines.push(" }");
|
|
151
|
+
dataOffset += getTypeSize(field.type);
|
|
152
|
+
}
|
|
153
|
+
lines.push("");
|
|
154
|
+
}
|
|
155
|
+
lines.push("}");
|
|
156
|
+
lines.push("");
|
|
157
|
+
}
|
|
158
|
+
function generateBuilder(struct, dataWords, pointerCount, lines) {
|
|
159
|
+
lines.push(`export class ${struct.name}Builder {`);
|
|
160
|
+
lines.push(" private builder: StructBuilder;");
|
|
161
|
+
lines.push("");
|
|
162
|
+
lines.push(" constructor(builder: StructBuilder) {");
|
|
163
|
+
lines.push(" this.builder = builder;");
|
|
164
|
+
lines.push(" }");
|
|
165
|
+
lines.push("");
|
|
166
|
+
lines.push(` static create(message: MessageBuilder): ${struct.name}Builder {`);
|
|
167
|
+
lines.push(` const root = message.initRoot(${dataWords}, ${pointerCount});`);
|
|
168
|
+
lines.push(` return new ${struct.name}Builder(root);`);
|
|
169
|
+
lines.push(" }");
|
|
170
|
+
lines.push("");
|
|
171
|
+
let dataOffset = 0;
|
|
172
|
+
let pointerIndex = 0;
|
|
173
|
+
for (const field of struct.fields) {
|
|
174
|
+
const tsType = mapTypeToTs(field.type);
|
|
175
|
+
const method = getSetterMethod(field.type);
|
|
176
|
+
if (isPointerType(field.type)) {
|
|
177
|
+
lines.push(` set${capitalize(field.name)}(value: ${tsType}): void {`);
|
|
178
|
+
lines.push(` this.builder.${method}(${pointerIndex}, value);`);
|
|
179
|
+
lines.push(" }");
|
|
180
|
+
pointerIndex++;
|
|
181
|
+
} else {
|
|
182
|
+
lines.push(` set${capitalize(field.name)}(value: ${tsType}): void {`);
|
|
183
|
+
lines.push(` this.builder.${method}(${dataOffset}, value);`);
|
|
184
|
+
lines.push(" }");
|
|
185
|
+
dataOffset += getTypeSize(field.type);
|
|
186
|
+
}
|
|
187
|
+
lines.push("");
|
|
188
|
+
}
|
|
189
|
+
lines.push("}");
|
|
190
|
+
lines.push("");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
//#endregion
|
|
194
|
+
//#region src/codegen/generator-v2.ts
|
|
195
|
+
/**
|
|
196
|
+
* Main code generator v2
|
|
197
|
+
*/
|
|
198
|
+
const DEFAULT_OPTIONS = { runtimeImportPath: "@naeemo/capnp" };
|
|
199
|
+
function generateCode(schema, options) {
|
|
200
|
+
const opts = {
|
|
201
|
+
...DEFAULT_OPTIONS,
|
|
202
|
+
...options
|
|
203
|
+
};
|
|
204
|
+
const lines = [];
|
|
205
|
+
lines.push("// Generated by capnp-ts-codegen");
|
|
206
|
+
lines.push("// DO NOT EDIT MANUALLY");
|
|
207
|
+
lines.push("");
|
|
208
|
+
lines.push(`import { MessageReader, MessageBuilder, StructReader, StructBuilder } from "${opts.runtimeImportPath}";`);
|
|
209
|
+
lines.push("");
|
|
210
|
+
for (const enum_ of schema.enums) generateEnum(enum_, lines);
|
|
211
|
+
for (const struct of schema.structs) generateStruct(struct, lines);
|
|
212
|
+
return lines.join("\n");
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
//#endregion
|
|
216
|
+
//#region src/codegen/parser-v2.ts
|
|
217
|
+
const PRIMITIVE_TYPES = new Set([
|
|
218
|
+
"Void",
|
|
219
|
+
"Bool",
|
|
220
|
+
"Int8",
|
|
221
|
+
"Int16",
|
|
222
|
+
"Int32",
|
|
223
|
+
"Int64",
|
|
224
|
+
"UInt8",
|
|
225
|
+
"UInt16",
|
|
226
|
+
"UInt32",
|
|
227
|
+
"UInt64",
|
|
228
|
+
"Float32",
|
|
229
|
+
"Float64",
|
|
230
|
+
"Text",
|
|
231
|
+
"Data"
|
|
232
|
+
]);
|
|
233
|
+
function isPrimitive(type) {
|
|
234
|
+
return PRIMITIVE_TYPES.has(type);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* 解析 Cap'n Proto schema
|
|
238
|
+
*
|
|
239
|
+
* 支持的语法:
|
|
240
|
+
* - Struct 定义
|
|
241
|
+
* - Enum 定义
|
|
242
|
+
* - 基础类型字段
|
|
243
|
+
* - List 类型
|
|
244
|
+
* - 嵌套 struct 引用
|
|
245
|
+
*
|
|
246
|
+
* 不支持的语法(会忽略或报错):
|
|
247
|
+
* - Union
|
|
248
|
+
* - Group
|
|
249
|
+
* - Interface
|
|
250
|
+
* - Const
|
|
251
|
+
* - Annotation
|
|
252
|
+
* - 默认值
|
|
253
|
+
*/
|
|
254
|
+
function parseSchemaV2(source) {
|
|
255
|
+
const structs = [];
|
|
256
|
+
const enums = [];
|
|
257
|
+
const cleanSource = source.replace(/#.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
258
|
+
const structRegex = /struct\s+(\w+)\s*\{([^}]*)\}/g;
|
|
259
|
+
let match;
|
|
260
|
+
while ((match = structRegex.exec(cleanSource)) !== null) {
|
|
261
|
+
const name = match[1];
|
|
262
|
+
const body = match[2];
|
|
263
|
+
const fields = parseFields(body);
|
|
264
|
+
structs.push({
|
|
265
|
+
name,
|
|
266
|
+
fields
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
const enumRegex = /enum\s+(\w+)\s*\{([^}]*)\}/g;
|
|
270
|
+
while ((match = enumRegex.exec(cleanSource)) !== null) {
|
|
271
|
+
const name = match[1];
|
|
272
|
+
const body = match[2];
|
|
273
|
+
const values = parseEnumValues(body);
|
|
274
|
+
enums.push({
|
|
275
|
+
name,
|
|
276
|
+
values
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
return {
|
|
280
|
+
structs,
|
|
281
|
+
enums
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function parseFields(body) {
|
|
285
|
+
const fields = [];
|
|
286
|
+
const fieldRegex = /(\w+)\s*@(\d+)\s*:\s*([^;]+);/g;
|
|
287
|
+
let match;
|
|
288
|
+
while ((match = fieldRegex.exec(body)) !== null) {
|
|
289
|
+
const name = match[1];
|
|
290
|
+
const index = Number.parseInt(match[2]);
|
|
291
|
+
const type = parseType(match[3].trim());
|
|
292
|
+
fields.push({
|
|
293
|
+
name,
|
|
294
|
+
index,
|
|
295
|
+
type
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
return fields.sort((a, b) => a.index - b.index);
|
|
299
|
+
}
|
|
300
|
+
function parseType(typeStr) {
|
|
301
|
+
const listMatch = typeStr.match(/^List\((.+)\)$/);
|
|
302
|
+
if (listMatch) return {
|
|
303
|
+
kind: "list",
|
|
304
|
+
elementType: parseType(listMatch[1].trim())
|
|
305
|
+
};
|
|
306
|
+
if (isPrimitive(typeStr)) return typeStr;
|
|
307
|
+
return {
|
|
308
|
+
kind: "struct",
|
|
309
|
+
name: typeStr
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
function parseEnumValues(body) {
|
|
313
|
+
const values = [];
|
|
314
|
+
const valueRegex = /(\w+)\s*@(\d+)\s*;/g;
|
|
315
|
+
let match;
|
|
316
|
+
while ((match = valueRegex.exec(body)) !== null) {
|
|
317
|
+
const name = match[1];
|
|
318
|
+
const index = Number.parseInt(match[2]);
|
|
319
|
+
values.push({
|
|
320
|
+
name,
|
|
321
|
+
index
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
return values.sort((a, b) => a.index - b.index);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
//#endregion
|
|
328
|
+
//#region src/cli.ts
|
|
329
|
+
/**
|
|
330
|
+
* Cap'n Proto CLI
|
|
331
|
+
*
|
|
332
|
+
* Usage:
|
|
333
|
+
* capnp gen schema.capnp -o types.ts
|
|
334
|
+
*/
|
|
335
|
+
const { values, positionals } = parseArgs({
|
|
336
|
+
args: process.argv.slice(2),
|
|
337
|
+
options: {
|
|
338
|
+
output: {
|
|
339
|
+
type: "string",
|
|
340
|
+
short: "o"
|
|
341
|
+
},
|
|
342
|
+
help: {
|
|
343
|
+
type: "boolean",
|
|
344
|
+
short: "h"
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
allowPositionals: true
|
|
348
|
+
});
|
|
349
|
+
if (values.help || positionals.length === 0) {
|
|
350
|
+
console.log(`
|
|
351
|
+
Cap'n Proto TypeScript CLI
|
|
352
|
+
|
|
353
|
+
Usage:
|
|
354
|
+
capnp gen <schema.capnp> [options] Generate TypeScript from schema
|
|
355
|
+
capnp --help Show this help
|
|
356
|
+
|
|
357
|
+
Options:
|
|
358
|
+
-o, --output Output file (default: stdout)
|
|
359
|
+
-h, --help Show this help
|
|
360
|
+
|
|
361
|
+
Examples:
|
|
362
|
+
npx @naeemo/capnp gen schema.capnp -o types.ts
|
|
363
|
+
capnp gen schema.capnp > types.ts
|
|
364
|
+
`);
|
|
365
|
+
process.exit(0);
|
|
366
|
+
}
|
|
367
|
+
const command = positionals[0];
|
|
368
|
+
if (command !== "gen") {
|
|
369
|
+
console.error(`Unknown command: ${command}`);
|
|
370
|
+
console.error("Run \"capnp --help\" for usage");
|
|
371
|
+
process.exit(1);
|
|
372
|
+
}
|
|
373
|
+
const inputFile = positionals[1];
|
|
374
|
+
if (!inputFile) {
|
|
375
|
+
console.error("Error: Missing input file");
|
|
376
|
+
console.error("Usage: capnp gen <schema.capnp>");
|
|
377
|
+
process.exit(1);
|
|
378
|
+
}
|
|
379
|
+
const outputFile = values.output;
|
|
380
|
+
async function main() {
|
|
381
|
+
const code = generateCode(parseSchemaV2(readFileSync(inputFile, "utf-8")));
|
|
382
|
+
if (outputFile) {
|
|
383
|
+
writeFileSync(outputFile, code);
|
|
384
|
+
console.error(`Generated: ${outputFile}`);
|
|
385
|
+
} else console.log(code);
|
|
386
|
+
}
|
|
387
|
+
main().catch((err) => {
|
|
388
|
+
console.error("Error:", err.message);
|
|
389
|
+
process.exit(1);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
//#endregion
|
|
393
|
+
export { };
|
|
394
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","names":[],"sources":["../src/codegen/enum-gen.ts","../src/codegen/type-utils.ts","../src/codegen/struct-gen.ts","../src/codegen/generator-v2.ts","../src/codegen/parser-v2.ts","../src/cli.ts"],"sourcesContent":["/**\n * Enum generator\n */\n\nexport function generateEnum(\n enum_: { name: string; values: { name: string; index: number }[] },\n lines: string[]\n): void {\n lines.push(`export enum ${enum_.name} {`);\n for (const value of enum_.values) {\n lines.push(` ${value.name} = ${value.index},`);\n }\n lines.push('}');\n lines.push('');\n}\n","/**\n * Type mapping utilities\n */\n\nimport type { Type } from './parser-v2.js';\n\nexport function isPointerType(type: Type): boolean {\n if (typeof type === 'string') {\n return type === 'Text' || type === 'Data';\n }\n return type.kind === 'list' || type.kind === 'struct';\n}\n\nexport function getTypeSize(type: Type): number {\n if (typeof type !== 'string') return 8;\n switch (type) {\n case 'Void':\n return 0;\n case 'Bool':\n return 1;\n case 'Int8':\n case 'UInt8':\n return 1;\n case 'Int16':\n case 'UInt16':\n return 2;\n case 'Int32':\n case 'UInt32':\n case 'Float32':\n return 4;\n case 'Int64':\n case 'UInt64':\n case 'Float64':\n return 8;\n default:\n return 8;\n }\n}\n\nexport function mapTypeToTs(type: Type): string {\n if (typeof type !== 'string') {\n if (type.kind === 'list') return `${mapTypeToTs(type.elementType)}[]`;\n return type.name;\n }\n switch (type) {\n case 'Void':\n return 'void';\n case 'Bool':\n return 'boolean';\n case 'Int8':\n case 'Int16':\n case 'Int32':\n case 'UInt8':\n case 'UInt16':\n case 'UInt32':\n case 'Float32':\n case 'Float64':\n return 'number';\n case 'Int64':\n case 'UInt64':\n return 'bigint';\n case 'Text':\n return 'string';\n case 'Data':\n return 'Uint8Array';\n default:\n return 'unknown';\n }\n}\n\nexport function getGetterMethod(type: Type): string {\n if (typeof type !== 'string') {\n if (type.kind === 'list') return 'getList';\n return 'getStruct';\n }\n switch (type) {\n case 'Void':\n return 'getVoid';\n case 'Bool':\n return 'getBool';\n case 'Int8':\n return 'getInt8';\n case 'Int16':\n return 'getInt16';\n case 'Int32':\n return 'getInt32';\n case 'Int64':\n return 'getInt64';\n case 'UInt8':\n return 'getUint8';\n case 'UInt16':\n return 'getUint16';\n case 'UInt32':\n return 'getUint32';\n case 'UInt64':\n return 'getUint64';\n case 'Float32':\n return 'getFloat32';\n case 'Float64':\n return 'getFloat64';\n case 'Text':\n return 'getText';\n case 'Data':\n return 'getData';\n default:\n return 'getUnknown';\n }\n}\n\nexport function getSetterMethod(type: Type): string {\n if (typeof type !== 'string') {\n if (type.kind === 'list') return 'initList';\n return 'initStruct';\n }\n switch (type) {\n case 'Void':\n return 'setVoid';\n case 'Bool':\n return 'setBool';\n case 'Int8':\n return 'setInt8';\n case 'Int16':\n return 'setInt16';\n case 'Int32':\n return 'setInt32';\n case 'Int64':\n return 'setInt64';\n case 'UInt8':\n return 'setUint8';\n case 'UInt16':\n return 'setUint16';\n case 'UInt32':\n return 'setUint32';\n case 'UInt64':\n return 'setUint64';\n case 'Float32':\n return 'setFloat32';\n case 'Float64':\n return 'setFloat64';\n case 'Text':\n return 'setText';\n case 'Data':\n return 'setData';\n default:\n return 'setUnknown';\n }\n}\n\nexport function capitalize(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n","/**\n * Struct generator\n */\n\nimport type { Struct } from './parser-v2.js';\nimport {\n capitalize,\n getGetterMethod,\n getSetterMethod,\n getTypeSize,\n isPointerType,\n mapTypeToTs,\n} from './type-utils.js';\n\nexport function generateStruct(struct: Struct, lines: string[]): void {\n let dataWords = 0;\n let pointerCount = 0;\n let dataOffset = 0;\n\n for (const field of struct.fields) {\n if (isPointerType(field.type)) {\n pointerCount++;\n } else {\n dataOffset += getTypeSize(field.type);\n }\n }\n dataWords = Math.ceil(dataOffset / 8);\n\n // Interface\n lines.push(`export interface ${struct.name} {`);\n for (const field of struct.fields) {\n lines.push(` ${field.name}: ${mapTypeToTs(field.type)};`);\n }\n lines.push('}');\n lines.push('');\n\n // Reader\n generateReader(struct, dataWords, pointerCount, lines);\n\n // Builder\n generateBuilder(struct, dataWords, pointerCount, lines);\n}\n\nfunction generateReader(\n struct: Struct,\n _dataWords: number,\n _pointerCount: number,\n lines: string[]\n): void {\n lines.push(`export class ${struct.name}Reader {`);\n lines.push(' private reader: StructReader;');\n lines.push('');\n lines.push(' constructor(reader: StructReader) {');\n lines.push(' this.reader = reader;');\n lines.push(' }');\n lines.push('');\n\n let dataOffset = 0;\n let pointerIndex = 0;\n for (const field of struct.fields) {\n const tsType = mapTypeToTs(field.type);\n if (isPointerType(field.type)) {\n lines.push(` get ${field.name}(): ${tsType} {`);\n lines.push(` return this.reader.${getGetterMethod(field.type)}(${pointerIndex});`);\n lines.push(' }');\n pointerIndex++;\n } else {\n lines.push(` get ${field.name}(): ${tsType} {`);\n lines.push(` return this.reader.${getGetterMethod(field.type)}(${dataOffset});`);\n lines.push(' }');\n dataOffset += getTypeSize(field.type);\n }\n lines.push('');\n }\n lines.push('}');\n lines.push('');\n}\n\nfunction generateBuilder(\n struct: Struct,\n dataWords: number,\n pointerCount: number,\n lines: string[]\n): void {\n lines.push(`export class ${struct.name}Builder {`);\n lines.push(' private builder: StructBuilder;');\n lines.push('');\n lines.push(' constructor(builder: StructBuilder) {');\n lines.push(' this.builder = builder;');\n lines.push(' }');\n lines.push('');\n lines.push(` static create(message: MessageBuilder): ${struct.name}Builder {`);\n lines.push(` const root = message.initRoot(${dataWords}, ${pointerCount});`);\n lines.push(` return new ${struct.name}Builder(root);`);\n lines.push(' }');\n lines.push('');\n\n let dataOffset = 0;\n let pointerIndex = 0;\n for (const field of struct.fields) {\n const tsType = mapTypeToTs(field.type);\n const method = getSetterMethod(field.type);\n if (isPointerType(field.type)) {\n lines.push(` set${capitalize(field.name)}(value: ${tsType}): void {`);\n lines.push(` this.builder.${method}(${pointerIndex}, value);`);\n lines.push(' }');\n pointerIndex++;\n } else {\n lines.push(` set${capitalize(field.name)}(value: ${tsType}): void {`);\n lines.push(` this.builder.${method}(${dataOffset}, value);`);\n lines.push(' }');\n dataOffset += getTypeSize(field.type);\n }\n lines.push('');\n }\n lines.push('}');\n lines.push('');\n}\n","/**\n * Main code generator v2\n */\n\nimport { generateEnum } from './enum-gen.js';\nimport type { Schema } from './parser-v2.js';\nimport { generateStruct } from './struct-gen.js';\n\nexport interface GeneratorOptions {\n runtimeImportPath?: string;\n}\n\nconst DEFAULT_OPTIONS: GeneratorOptions = {\n runtimeImportPath: '@naeemo/capnp',\n};\n\nexport function generateCode(schema: Schema, options?: GeneratorOptions): string {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n const lines: string[] = [];\n\n lines.push('// Generated by capnp-ts-codegen');\n lines.push('// DO NOT EDIT MANUALLY');\n lines.push('');\n lines.push(\n `import { MessageReader, MessageBuilder, StructReader, StructBuilder } from \"${opts.runtimeImportPath}\";`\n );\n lines.push('');\n\n for (const enum_ of schema.enums) {\n generateEnum(enum_, lines);\n }\n\n for (const struct of schema.structs) {\n generateStruct(struct, lines);\n }\n\n return lines.join('\\n');\n}\n","/**\n * Cap'n Proto Schema 解析器 v2 - 简化版\n * 基于正则的解析器,支持常用 Cap'n Proto 语法\n */\n\n// 基础类型\nexport type PrimitiveType =\n | 'Void'\n | 'Bool'\n | 'Int8'\n | 'Int16'\n | 'Int32'\n | 'Int64'\n | 'UInt8'\n | 'UInt16'\n | 'UInt32'\n | 'UInt64'\n | 'Float32'\n | 'Float64'\n | 'Text'\n | 'Data';\n\nexport interface ListType {\n kind: 'list';\n elementType: Type;\n}\n\nexport interface StructType {\n kind: 'struct';\n name: string;\n}\n\nexport type Type = PrimitiveType | ListType | StructType;\n\nexport interface Field {\n name: string;\n index: number;\n type: Type;\n}\n\nexport interface Struct {\n name: string;\n fields: Field[];\n}\n\nexport interface EnumValue {\n name: string;\n index: number;\n}\n\nexport interface Enum {\n name: string;\n values: EnumValue[];\n}\n\nexport interface Schema {\n structs: Struct[];\n enums: Enum[];\n}\n\nconst PRIMITIVE_TYPES: Set<string> = new Set([\n 'Void',\n 'Bool',\n 'Int8',\n 'Int16',\n 'Int32',\n 'Int64',\n 'UInt8',\n 'UInt16',\n 'UInt32',\n 'UInt64',\n 'Float32',\n 'Float64',\n 'Text',\n 'Data',\n]);\n\nfunction isPrimitive(type: string): type is PrimitiveType {\n return PRIMITIVE_TYPES.has(type);\n}\n\n/**\n * 解析 Cap'n Proto schema\n *\n * 支持的语法:\n * - Struct 定义\n * - Enum 定义\n * - 基础类型字段\n * - List 类型\n * - 嵌套 struct 引用\n *\n * 不支持的语法(会忽略或报错):\n * - Union\n * - Group\n * - Interface\n * - Const\n * - Annotation\n * - 默认值\n */\nexport function parseSchemaV2(source: string): Schema {\n const structs: Struct[] = [];\n const enums: Enum[] = [];\n\n // 移除注释\n const cleanSource = source\n .replace(/#.*$/gm, '') // 行注释\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, ''); // 块注释\n\n // 解析 struct\n const structRegex = /struct\\s+(\\w+)\\s*\\{([^}]*)\\}/g;\n let match;\n while ((match = structRegex.exec(cleanSource)) !== null) {\n const name = match[1];\n const body = match[2];\n const fields = parseFields(body);\n structs.push({ name, fields });\n }\n\n // 解析 enum\n const enumRegex = /enum\\s+(\\w+)\\s*\\{([^}]*)\\}/g;\n while ((match = enumRegex.exec(cleanSource)) !== null) {\n const name = match[1];\n const body = match[2];\n const values = parseEnumValues(body);\n enums.push({ name, values });\n }\n\n return { structs, enums };\n}\n\nfunction parseFields(body: string): Field[] {\n const fields: Field[] = [];\n\n // 字段格式: name @index :Type;\n const fieldRegex = /(\\w+)\\s*@(\\d+)\\s*:\\s*([^;]+);/g;\n let match;\n\n while ((match = fieldRegex.exec(body)) !== null) {\n const name = match[1];\n const index = Number.parseInt(match[2]);\n const typeStr = match[3].trim();\n const type = parseType(typeStr);\n\n fields.push({ name, index, type });\n }\n\n return fields.sort((a, b) => a.index - b.index);\n}\n\nfunction parseType(typeStr: string): Type {\n // 检查 List 类型\n const listMatch = typeStr.match(/^List\\((.+)\\)$/);\n if (listMatch) {\n const elementType = parseType(listMatch[1].trim());\n return { kind: 'list', elementType };\n }\n\n // 检查基础类型\n if (isPrimitive(typeStr)) {\n return typeStr;\n }\n\n // 假设是 struct 类型\n return { kind: 'struct', name: typeStr };\n}\n\nfunction parseEnumValues(body: string): EnumValue[] {\n const values: EnumValue[] = [];\n\n // 格式: name @index;\n const valueRegex = /(\\w+)\\s*@(\\d+)\\s*;/g;\n let match;\n\n while ((match = valueRegex.exec(body)) !== null) {\n const name = match[1];\n const index = Number.parseInt(match[2]);\n values.push({ name, index });\n }\n\n return values.sort((a, b) => a.index - b.index);\n}\n","#!/usr/bin/env node\n\n/**\n * Cap'n Proto CLI\n *\n * Usage:\n * capnp gen schema.capnp -o types.ts\n */\n\nimport { readFileSync, writeFileSync } from 'node:fs';\nimport { parseArgs } from 'node:util';\nimport { generateCode } from './codegen/generator-v2.js';\nimport { parseSchemaV2 } from './codegen/parser-v2.js';\n\nconst { values, positionals } = parseArgs({\n args: process.argv.slice(2),\n options: {\n output: { type: 'string', short: 'o' },\n help: { type: 'boolean', short: 'h' },\n },\n allowPositionals: true,\n});\n\nif (values.help || positionals.length === 0) {\n console.log(`\nCap'n Proto TypeScript CLI\n\nUsage:\n capnp gen <schema.capnp> [options] Generate TypeScript from schema\n capnp --help Show this help\n\nOptions:\n -o, --output Output file (default: stdout)\n -h, --help Show this help\n\nExamples:\n npx @naeemo/capnp gen schema.capnp -o types.ts\n capnp gen schema.capnp > types.ts\n`);\n process.exit(0);\n}\n\nconst command = positionals[0];\n\nif (command !== 'gen') {\n console.error(`Unknown command: ${command}`);\n console.error('Run \"capnp --help\" for usage');\n process.exit(1);\n}\n\nconst inputFile = positionals[1];\nif (!inputFile) {\n console.error('Error: Missing input file');\n console.error('Usage: capnp gen <schema.capnp>');\n process.exit(1);\n}\n\nconst outputFile = values.output;\n\nasync function main() {\n const source = readFileSync(inputFile, 'utf-8');\n const schema = parseSchemaV2(source);\n const code = generateCode(schema);\n\n if (outputFile) {\n writeFileSync(outputFile, code);\n console.error(`Generated: ${outputFile}`);\n } else {\n console.log(code);\n }\n}\n\nmain().catch((err) => {\n console.error('Error:', err.message);\n process.exit(1);\n});\n"],"mappings":"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"}
|