@chnak/zod-to-markdown 1.0.1 → 1.0.3
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/.claude/settings.local.json +7 -0
- package/README.md +73 -4
- package/examples/company-schema-table.md +18 -0
- package/examples/complex-schema-table.ts +60 -0
- package/examples/nested-object-example.md +11 -0
- package/examples/nested-object-example.ts +42 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +207 -1
- package/lib/index.test.js +78 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# zod-to-markdown
|
|
2
2
|
|
|
3
|
-
将 Zod schema 转换为 Markdown
|
|
3
|
+
将 Zod schema 转换为 Markdown 文档的工具函数,支持两种输出格式:树状列表和表格。
|
|
4
4
|
|
|
5
5
|
## 安装
|
|
6
6
|
|
|
@@ -13,7 +13,7 @@ npm install @chnak/zod-to-markdown
|
|
|
13
13
|
### ESM / TypeScript
|
|
14
14
|
|
|
15
15
|
```typescript
|
|
16
|
-
import { zodSchemaToMarkdown } from '@chnak/zod-to-markdown';
|
|
16
|
+
import { zodSchemaToMarkdown, zodSchemaToTable } from '@chnak/zod-to-markdown';
|
|
17
17
|
import { z } from 'zod';
|
|
18
18
|
|
|
19
19
|
const schema = z.object({
|
|
@@ -21,14 +21,19 @@ const schema = z.object({
|
|
|
21
21
|
age: z.number(),
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
+
// 树状格式
|
|
24
25
|
const markdown = zodSchemaToMarkdown(schema);
|
|
25
26
|
console.log(markdown);
|
|
27
|
+
|
|
28
|
+
// 表格格式
|
|
29
|
+
const table = zodSchemaToTable(schema);
|
|
30
|
+
console.log(table);
|
|
26
31
|
```
|
|
27
32
|
|
|
28
33
|
### CommonJS / Node.js
|
|
29
34
|
|
|
30
35
|
```javascript
|
|
31
|
-
const { zodSchemaToMarkdown } = require('@chnak/zod-to-markdown');
|
|
36
|
+
const { zodSchemaToMarkdown, zodSchemaToTable } = require('@chnak/zod-to-markdown');
|
|
32
37
|
const { z } = require('zod');
|
|
33
38
|
|
|
34
39
|
const schema = z.object({
|
|
@@ -37,11 +42,15 @@ const schema = z.object({
|
|
|
37
42
|
});
|
|
38
43
|
|
|
39
44
|
const markdown = zodSchemaToMarkdown(schema);
|
|
45
|
+
const table = zodSchemaToTable(schema);
|
|
40
46
|
console.log(markdown);
|
|
47
|
+
console.log(table);
|
|
41
48
|
```
|
|
42
49
|
|
|
43
50
|
### 输出结果
|
|
44
51
|
|
|
52
|
+
**树状格式 (`zodSchemaToMarkdown`)**:
|
|
53
|
+
|
|
45
54
|
```markdown
|
|
46
55
|
- name
|
|
47
56
|
- String
|
|
@@ -49,6 +58,15 @@ console.log(markdown);
|
|
|
49
58
|
- Number
|
|
50
59
|
```
|
|
51
60
|
|
|
61
|
+
**表格格式 (`zodSchemaToTable`)**:
|
|
62
|
+
|
|
63
|
+
```markdown
|
|
64
|
+
| 字段 | 类型 | 描述 |
|
|
65
|
+
|------|------|------|
|
|
66
|
+
| name | String | - |
|
|
67
|
+
| age | Number | - |
|
|
68
|
+
```
|
|
69
|
+
|
|
52
70
|
## 支持的 Zod 类型
|
|
53
71
|
|
|
54
72
|
### 基础类型
|
|
@@ -161,6 +179,49 @@ console.log(zodSchemaToMarkdown(transformedSchema));
|
|
|
161
179
|
- String
|
|
162
180
|
```
|
|
163
181
|
|
|
182
|
+
### 表格格式示例
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
import { z } from 'zod';
|
|
186
|
+
|
|
187
|
+
const userSchema = z.object({
|
|
188
|
+
id: z.string().uuid().describe('用户ID'),
|
|
189
|
+
name: z.string().describe('姓名'),
|
|
190
|
+
profile: z.object({
|
|
191
|
+
bio: z.string().describe('个人简介'),
|
|
192
|
+
avatar: z.string().describe('头像URL'),
|
|
193
|
+
}).describe('用户资料'),
|
|
194
|
+
tags: z.array(z.string()).describe('标签'),
|
|
195
|
+
skills: z.record(z.string(), z.number()).describe('技能评分'),
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
console.log(zodSchemaToTable(userSchema));
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
输出:
|
|
202
|
+
```markdown
|
|
203
|
+
| 字段 | 类型 | 描述 |
|
|
204
|
+
|------|------|------|
|
|
205
|
+
| id | String | 用户ID |
|
|
206
|
+
| name | String | 姓名 |
|
|
207
|
+
| profile.bio | String | 个人简介 |
|
|
208
|
+
| profile.avatar | String | 头像URL |
|
|
209
|
+
| tags[] | Array<String> | 标签 |
|
|
210
|
+
| skills | Record<String, Number> | 技能评分 |
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### 路径格式说明
|
|
214
|
+
|
|
215
|
+
表格格式使用点 `.` 和 `[]` 表示嵌套结构:
|
|
216
|
+
|
|
217
|
+
| 格式 | 含义 | 示例 |
|
|
218
|
+
|------|------|------|
|
|
219
|
+
| `field` | 普通字段 | `name` |
|
|
220
|
+
| `parent.child` | 对象嵌套 | `profile.bio` |
|
|
221
|
+
| `field[]` | 数组 | `tags[]` |
|
|
222
|
+
| `array[].field` | 对象数组的字段 | `users[].name` |
|
|
223
|
+
| `a[].b[].c` | 多层嵌套 | `departments[].employees[].name` |
|
|
224
|
+
|
|
164
225
|
## API
|
|
165
226
|
|
|
166
227
|
### `zodSchemaToMarkdown(schema, indentLevel?)`
|
|
@@ -170,7 +231,15 @@ console.log(zodSchemaToMarkdown(transformedSchema));
|
|
|
170
231
|
| `schema` | `z.ZodTypeAny` | 要转换的 Zod schema |
|
|
171
232
|
| `indentLevel` | `number` | 初始缩进级别(默认: `0`) |
|
|
172
233
|
|
|
173
|
-
|
|
234
|
+
返回树状格式的 Markdown 字符串。
|
|
235
|
+
|
|
236
|
+
### `zodSchemaToTable(schema)`
|
|
237
|
+
|
|
238
|
+
| 参数 | 类型 | 说明 |
|
|
239
|
+
|------|------|------|
|
|
240
|
+
| `schema` | `z.ZodTypeAny` | 要转换的 Zod schema(仅支持 ZodObject) |
|
|
241
|
+
|
|
242
|
+
返回表格格式的 Markdown 字符串。非 ZodObject 类型会回退到树状格式。
|
|
174
243
|
|
|
175
244
|
## License
|
|
176
245
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
| 字段 | 类型 | 描述 |
|
|
2
|
+
|------|------|------|
|
|
3
|
+
| id | String | 公司ID |
|
|
4
|
+
| name | String | 公司名称 |
|
|
5
|
+
| departments[].name | String | 部门名称 |
|
|
6
|
+
| departments[].employees[].id | String | 员工ID |
|
|
7
|
+
| departments[].employees[].name | String | 姓名 |
|
|
8
|
+
| departments[].employees[].title | String | 职位 |
|
|
9
|
+
| departments[].employees[].skills[] | Array<String> | 技能 |
|
|
10
|
+
| departments[].employees[].contact.email | String | 邮箱 |
|
|
11
|
+
| departments[].employees[].contact.phone | Optional<String> | 电话 |
|
|
12
|
+
| departments[].location.street | String | 街道 |
|
|
13
|
+
| departments[].location.city | String | 城市 |
|
|
14
|
+
| departments[].location.country | String | 国家 |
|
|
15
|
+
| departments[].location.coordinates.lat | Number | 纬度 |
|
|
16
|
+
| departments[].location.coordinates.lng | Number | 经度 |
|
|
17
|
+
| foundedYear | Number | 成立年份 |
|
|
18
|
+
| tags[] | Array<String> | 标签 |
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { zodSchemaToTable } from '../src/index';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
|
|
5
|
+
// 多层嵌套 Schema 示例
|
|
6
|
+
|
|
7
|
+
// 第一层:坐标
|
|
8
|
+
const coordinatesSchema = z.object({
|
|
9
|
+
lat: z.number().describe('纬度'),
|
|
10
|
+
lng: z.number().describe('经度'),
|
|
11
|
+
}).describe('地理坐标');
|
|
12
|
+
|
|
13
|
+
// 第二层:地址
|
|
14
|
+
const addressSchema = z.object({
|
|
15
|
+
street: z.string().describe('街道'),
|
|
16
|
+
city: z.string().describe('城市'),
|
|
17
|
+
country: z.string().describe('国家'),
|
|
18
|
+
coordinates: coordinatesSchema.describe('坐标'),
|
|
19
|
+
}).describe('地址');
|
|
20
|
+
|
|
21
|
+
// 爱好
|
|
22
|
+
const hobbySchema = z.object({
|
|
23
|
+
name: z.string().describe('爱好名称'),
|
|
24
|
+
level: z.enum(['beginner', 'intermediate', 'advanced']).describe('等级'),
|
|
25
|
+
equipment: z.array(z.object({
|
|
26
|
+
name: z.string().describe('装备名称'),
|
|
27
|
+
brand: z.string().optional().describe('品牌'),
|
|
28
|
+
})).optional().describe('相关装备'),
|
|
29
|
+
}).describe('爱好');
|
|
30
|
+
|
|
31
|
+
// 主要 Schema
|
|
32
|
+
const companySchema = z.object({
|
|
33
|
+
id: z.string().uuid().describe('公司ID'),
|
|
34
|
+
name: z.string().describe('公司名称'),
|
|
35
|
+
departments: z.array(z.object({
|
|
36
|
+
name: z.string().describe('部门名称'),
|
|
37
|
+
employees: z.array(z.object({
|
|
38
|
+
id: z.string().describe('员工ID'),
|
|
39
|
+
name: z.string().describe('姓名'),
|
|
40
|
+
title: z.string().describe('职位'),
|
|
41
|
+
skills: z.array(z.string()).describe('技能'),
|
|
42
|
+
contact: z.object({
|
|
43
|
+
email: z.string().describe('邮箱'),
|
|
44
|
+
phone: z.string().optional().describe('电话'),
|
|
45
|
+
}).describe('联系方式'),
|
|
46
|
+
})).describe('员工列表'),
|
|
47
|
+
location: addressSchema.describe('部门地址'),
|
|
48
|
+
})).describe('部门列表'),
|
|
49
|
+
foundedYear: z.number().describe('成立年份'),
|
|
50
|
+
tags: z.array(z.string()).describe('标签'),
|
|
51
|
+
}).describe('公司');
|
|
52
|
+
|
|
53
|
+
const markdown = zodSchemaToTable(companySchema);
|
|
54
|
+
|
|
55
|
+
console.log('## Company Schema 文档 (多层级嵌套)\n');
|
|
56
|
+
console.log(markdown);
|
|
57
|
+
|
|
58
|
+
// 保存到文件
|
|
59
|
+
fs.writeFileSync('examples/company-schema-table.md', markdown);
|
|
60
|
+
console.log('\n已保存到 examples/company-schema-table.md');
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
| 字段 | 类型 | 描述 |
|
|
2
|
+
|------|------|------|
|
|
3
|
+
| id | String | 用户ID |
|
|
4
|
+
| name | String | 姓名 |
|
|
5
|
+
| profile.bio | String | 个人简介 |
|
|
6
|
+
| profile.avatar | String | 头像URL |
|
|
7
|
+
| profile.age | Number | 年龄 |
|
|
8
|
+
| settings.theme | Enum(light | dark) | 主题 |
|
|
9
|
+
| settings.language | String | 语言 |
|
|
10
|
+
| settings.notifications.email | Boolean | 邮件通知 |
|
|
11
|
+
| settings.notifications.push | Boolean | 推送通知 |
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { zodSchemaToTable } from '../src/index';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
|
|
5
|
+
// 纯对象嵌套示例
|
|
6
|
+
const coordinatesSchema = z.object({
|
|
7
|
+
lat: z.number().describe('纬度'),
|
|
8
|
+
lng: z.number().describe('经度'),
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const addressSchema = z.object({
|
|
12
|
+
street: z.string().describe('街道'),
|
|
13
|
+
city: z.string().describe('城市'),
|
|
14
|
+
country: z.string().describe('国家'),
|
|
15
|
+
coordinates: coordinatesSchema.describe('坐标'),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const userSchema = z.object({
|
|
19
|
+
id: z.string().uuid().describe('用户ID'),
|
|
20
|
+
name: z.string().describe('姓名'),
|
|
21
|
+
profile: z.object({
|
|
22
|
+
bio: z.string().describe('个人简介'),
|
|
23
|
+
avatar: z.string().describe('头像URL'),
|
|
24
|
+
age: z.number().describe('年龄'),
|
|
25
|
+
}).describe('用户资料'),
|
|
26
|
+
settings: z.object({
|
|
27
|
+
theme: z.enum(['light', 'dark']).describe('主题'),
|
|
28
|
+
language: z.string().describe('语言'),
|
|
29
|
+
notifications: z.object({
|
|
30
|
+
email: z.boolean().describe('邮件通知'),
|
|
31
|
+
push: z.boolean().describe('推送通知'),
|
|
32
|
+
}).describe('通知设置'),
|
|
33
|
+
}).describe('设置'),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const markdown = zodSchemaToTable(userSchema);
|
|
37
|
+
|
|
38
|
+
console.log('## User Schema (Object 嵌套)\n');
|
|
39
|
+
console.log(markdown);
|
|
40
|
+
|
|
41
|
+
fs.writeFileSync('examples/nested-object-example.md', markdown);
|
|
42
|
+
console.log('已保存到 examples/nested-object-example.md');
|
package/lib/index.d.ts
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* 将 Zod schema 转换为表格形式的 Markdown
|
|
4
|
+
* @param schema - 要转换的 Zod schema
|
|
5
|
+
* @returns 表格形式的 Markdown 字符串
|
|
6
|
+
*/
|
|
7
|
+
export declare function zodSchemaToTable(schema: z.ZodTypeAny): string;
|
|
2
8
|
export declare function zodSchemaToMarkdown(schema: z.ZodTypeAny, indentLevel?: number): string;
|
package/lib/index.js
CHANGED
|
@@ -1,7 +1,213 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.zodSchemaToMarkdown = void 0;
|
|
3
|
+
exports.zodSchemaToMarkdown = exports.zodSchemaToTable = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
/**
|
|
6
|
+
* 将 Zod schema 转换为表格形式的 Markdown
|
|
7
|
+
* @param schema - 要转换的 Zod schema
|
|
8
|
+
* @returns 表格形式的 Markdown 字符串
|
|
9
|
+
*/
|
|
10
|
+
function zodSchemaToTable(schema) {
|
|
11
|
+
if (!(schema instanceof zod_1.z.ZodObject)) {
|
|
12
|
+
return zodSchemaToMarkdown(schema);
|
|
13
|
+
}
|
|
14
|
+
// 收集所有嵌套字段
|
|
15
|
+
const fields = [];
|
|
16
|
+
collectFields(schema, '', fields);
|
|
17
|
+
// 表头
|
|
18
|
+
const rows = [];
|
|
19
|
+
rows.push('| 字段 | 类型 | 描述 |');
|
|
20
|
+
rows.push('|------|------|------|');
|
|
21
|
+
fields.forEach(({ path, type, description }) => {
|
|
22
|
+
rows.push(`| ${path} | ${type} | ${description} |`);
|
|
23
|
+
});
|
|
24
|
+
return rows.join('\n') + '\n';
|
|
25
|
+
}
|
|
26
|
+
exports.zodSchemaToTable = zodSchemaToTable;
|
|
27
|
+
/**
|
|
28
|
+
* 递归收集所有嵌套字段
|
|
29
|
+
*/
|
|
30
|
+
function collectFields(schema, prefix, fields) {
|
|
31
|
+
// 处理 Optional - 包装类型
|
|
32
|
+
if (schema instanceof zod_1.z.ZodOptional) {
|
|
33
|
+
const innerType = getTypeString(schema.unwrap());
|
|
34
|
+
// 对于简单类型直接包装
|
|
35
|
+
if (schema.unwrap() instanceof zod_1.z.ZodObject || schema.unwrap() instanceof zod_1.z.ZodArray) {
|
|
36
|
+
collectFields(schema.unwrap(), prefix, fields);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
fields.push({
|
|
40
|
+
path: prefix,
|
|
41
|
+
type: `Optional<${innerType}>`,
|
|
42
|
+
description: schema.description || '-',
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// 处理 Nullable - 包装类型
|
|
48
|
+
if (schema instanceof zod_1.z.ZodNullable) {
|
|
49
|
+
const innerType = getTypeString(schema.unwrap());
|
|
50
|
+
if (schema.unwrap() instanceof zod_1.z.ZodObject || schema.unwrap() instanceof zod_1.z.ZodArray) {
|
|
51
|
+
collectFields(schema.unwrap(), prefix, fields);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
fields.push({
|
|
55
|
+
path: prefix,
|
|
56
|
+
type: `Nullable<${innerType}>`,
|
|
57
|
+
description: schema.description || '-',
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
// 处理 Default
|
|
63
|
+
if (schema instanceof zod_1.z.ZodDefault) {
|
|
64
|
+
collectFields(schema.removeDefault(), prefix, fields);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// 处理 Array - 收集元素类型
|
|
68
|
+
if (schema instanceof zod_1.z.ZodArray) {
|
|
69
|
+
const element = schema.element;
|
|
70
|
+
// 如果是对象数组,展开其字段
|
|
71
|
+
if (element instanceof zod_1.z.ZodObject) {
|
|
72
|
+
const innerFields = [];
|
|
73
|
+
collectFields(element, '', innerFields);
|
|
74
|
+
innerFields.forEach(field => {
|
|
75
|
+
const fieldPath = field.path || 'value';
|
|
76
|
+
fields.push({
|
|
77
|
+
path: `${prefix}[].${fieldPath}`,
|
|
78
|
+
type: field.type,
|
|
79
|
+
description: field.description,
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
// 非对象数组,保持原样
|
|
85
|
+
fields.push({
|
|
86
|
+
path: `${prefix}[]`,
|
|
87
|
+
type: getTypeString(schema),
|
|
88
|
+
description: schema.description || '-',
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
// 处理 ZodObject - 递归展开
|
|
94
|
+
if (schema instanceof zod_1.z.ZodObject) {
|
|
95
|
+
const shape = schema.shape;
|
|
96
|
+
Object.keys(shape).forEach(key => {
|
|
97
|
+
const subSchema = shape[key];
|
|
98
|
+
const newPath = prefix ? `${prefix}.${key}` : key;
|
|
99
|
+
collectFields(subSchema, newPath, fields);
|
|
100
|
+
});
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
// 处理 Record
|
|
104
|
+
if (schema instanceof zod_1.z.ZodRecord) {
|
|
105
|
+
fields.push({
|
|
106
|
+
path: prefix,
|
|
107
|
+
type: `Record<${getTypeString(schema.keySchema)}, ${getTypeString(schema.valueSchema)}>`,
|
|
108
|
+
description: schema.description || '-',
|
|
109
|
+
});
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
// 处理 Tuple
|
|
113
|
+
if (schema instanceof zod_1.z.ZodTuple) {
|
|
114
|
+
const items = schema.items.map((item) => getTypeString(item)).join(', ');
|
|
115
|
+
fields.push({
|
|
116
|
+
path: prefix,
|
|
117
|
+
type: `Tuple(${items})`,
|
|
118
|
+
description: schema.description || '-',
|
|
119
|
+
});
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
// 其他类型直接添加
|
|
123
|
+
fields.push({
|
|
124
|
+
path: prefix,
|
|
125
|
+
type: getTypeString(schema),
|
|
126
|
+
description: schema.description || '-',
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* 获取类型的字符串描述
|
|
131
|
+
*/
|
|
132
|
+
function getTypeString(schema) {
|
|
133
|
+
if (schema instanceof zod_1.z.ZodOptional) {
|
|
134
|
+
return `Optional<${getTypeString(schema.unwrap())}>`;
|
|
135
|
+
}
|
|
136
|
+
if (schema instanceof zod_1.z.ZodNullable) {
|
|
137
|
+
return `Nullable<${getTypeString(schema.unwrap())}>`;
|
|
138
|
+
}
|
|
139
|
+
if (schema instanceof zod_1.z.ZodDefault) {
|
|
140
|
+
return `Default<${getTypeString(schema.removeDefault())}>`;
|
|
141
|
+
}
|
|
142
|
+
if (schema instanceof zod_1.z.ZodArray) {
|
|
143
|
+
return `Array<${getTypeString(schema.element)}>`;
|
|
144
|
+
}
|
|
145
|
+
if (schema instanceof zod_1.z.ZodString) {
|
|
146
|
+
let result = 'String';
|
|
147
|
+
if (schema.minLength !== null || schema.maxLength !== null) {
|
|
148
|
+
const constraints = [];
|
|
149
|
+
if (schema.minLength !== null)
|
|
150
|
+
constraints.push(`min: ${schema.minLength}`);
|
|
151
|
+
if (schema.maxLength !== null)
|
|
152
|
+
constraints.push(`max: ${schema.maxLength}`);
|
|
153
|
+
result += ` (${constraints.join(', ')})`;
|
|
154
|
+
}
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
if (schema instanceof zod_1.z.ZodNumber) {
|
|
158
|
+
let result = 'Number';
|
|
159
|
+
if (schema.minValue !== null || schema.maxValue !== null) {
|
|
160
|
+
const constraints = [];
|
|
161
|
+
if (schema.minValue !== null)
|
|
162
|
+
constraints.push(`min: ${schema.minValue}`);
|
|
163
|
+
if (schema.maxValue !== null)
|
|
164
|
+
constraints.push(`max: ${schema.maxValue}`);
|
|
165
|
+
result += ` (${constraints.join(', ')})`;
|
|
166
|
+
}
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
169
|
+
if (schema instanceof zod_1.z.ZodEnum) {
|
|
170
|
+
return `Enum(${schema.options.join(' | ')})`;
|
|
171
|
+
}
|
|
172
|
+
if (schema instanceof zod_1.z.ZodLiteral) {
|
|
173
|
+
return `Literal(${JSON.stringify(schema.value)})`;
|
|
174
|
+
}
|
|
175
|
+
if (schema instanceof zod_1.z.ZodBoolean)
|
|
176
|
+
return 'Boolean';
|
|
177
|
+
if (schema instanceof zod_1.z.ZodBigInt)
|
|
178
|
+
return 'BigInt';
|
|
179
|
+
if (schema instanceof zod_1.z.ZodDate)
|
|
180
|
+
return 'Date';
|
|
181
|
+
if (schema instanceof zod_1.z.ZodNaN)
|
|
182
|
+
return 'NaN';
|
|
183
|
+
if (schema instanceof zod_1.z.ZodNever)
|
|
184
|
+
return 'Never';
|
|
185
|
+
if (schema instanceof zod_1.z.ZodUnknown)
|
|
186
|
+
return 'Unknown';
|
|
187
|
+
if (schema instanceof zod_1.z.ZodVoid)
|
|
188
|
+
return 'Void';
|
|
189
|
+
if (schema instanceof zod_1.z.ZodRecord) {
|
|
190
|
+
return `Record<${getTypeString(schema.keySchema)}, ${getTypeString(schema.valueSchema)}>`;
|
|
191
|
+
}
|
|
192
|
+
if (schema instanceof zod_1.z.ZodTuple) {
|
|
193
|
+
const items = schema.items.map((item) => getTypeString(item)).join(', ');
|
|
194
|
+
return `Tuple(${items})`;
|
|
195
|
+
}
|
|
196
|
+
if (schema instanceof zod_1.z.ZodUnion) {
|
|
197
|
+
const options = schema.options.map((opt) => getTypeString(opt)).join(' | ');
|
|
198
|
+
return `Union(${options})`;
|
|
199
|
+
}
|
|
200
|
+
if (schema instanceof zod_1.z.ZodDiscriminatedUnion) {
|
|
201
|
+
return `DiscriminatedUnion(${schema.discriminator})`;
|
|
202
|
+
}
|
|
203
|
+
if (schema instanceof zod_1.z.ZodIntersection) {
|
|
204
|
+
return 'Intersection';
|
|
205
|
+
}
|
|
206
|
+
if (schema instanceof zod_1.z.ZodEffects) {
|
|
207
|
+
return `Effects(${schema._def.effect.type})`;
|
|
208
|
+
}
|
|
209
|
+
return schema.constructor.name;
|
|
210
|
+
}
|
|
5
211
|
function zodSchemaToMarkdown(schema, indentLevel = 0) {
|
|
6
212
|
let markdown = "";
|
|
7
213
|
const indent = " ".repeat(indentLevel);
|
package/lib/index.test.js
CHANGED
|
@@ -131,3 +131,81 @@ describe('zodSchemaToMarkdown', () => {
|
|
|
131
131
|
expect((0, index_1.zodSchemaToMarkdown)(schema)).toBe(expected);
|
|
132
132
|
});
|
|
133
133
|
});
|
|
134
|
+
describe('zodSchemaToTable', () => {
|
|
135
|
+
it('should convert a simple object schema to table', () => {
|
|
136
|
+
const schema = zod_1.z.object({
|
|
137
|
+
name: zod_1.z.string(),
|
|
138
|
+
age: zod_1.z.number(),
|
|
139
|
+
});
|
|
140
|
+
const expected = `| 字段 | 类型 | 描述 |
|
|
141
|
+
|------|------|------|
|
|
142
|
+
| name | String | - |
|
|
143
|
+
| age | Number | - |
|
|
144
|
+
`;
|
|
145
|
+
expect((0, index_1.zodSchemaToTable)(schema)).toBe(expected);
|
|
146
|
+
});
|
|
147
|
+
it('should convert object schema with optional and nullable to table', () => {
|
|
148
|
+
const schema = zod_1.z.object({
|
|
149
|
+
name: zod_1.z.string().optional(),
|
|
150
|
+
email: zod_1.z.string().nullable(),
|
|
151
|
+
});
|
|
152
|
+
const expected = `| 字段 | 类型 | 描述 |
|
|
153
|
+
|------|------|------|
|
|
154
|
+
| name | Optional<String> | - |
|
|
155
|
+
| email | Nullable<String> | - |
|
|
156
|
+
`;
|
|
157
|
+
expect((0, index_1.zodSchemaToTable)(schema)).toBe(expected);
|
|
158
|
+
});
|
|
159
|
+
it('should convert object schema with enum to table', () => {
|
|
160
|
+
const schema = zod_1.z.object({
|
|
161
|
+
role: zod_1.z.enum(['admin', 'user', 'guest']),
|
|
162
|
+
});
|
|
163
|
+
const expected = `| 字段 | 类型 | 描述 |
|
|
164
|
+
|------|------|------|
|
|
165
|
+
| role | Enum(admin | user | guest) | - |
|
|
166
|
+
`;
|
|
167
|
+
expect((0, index_1.zodSchemaToTable)(schema)).toBe(expected);
|
|
168
|
+
});
|
|
169
|
+
it('should convert object schema with array to table', () => {
|
|
170
|
+
const schema = zod_1.z.object({
|
|
171
|
+
tags: zod_1.z.array(zod_1.z.string()),
|
|
172
|
+
scores: zod_1.z.array(zod_1.z.number()),
|
|
173
|
+
});
|
|
174
|
+
const expected = `| 字段 | 类型 | 描述 |
|
|
175
|
+
|------|------|------|
|
|
176
|
+
| tags[] | Array<String> | - |
|
|
177
|
+
| scores[] | Array<Number> | - |
|
|
178
|
+
`;
|
|
179
|
+
expect((0, index_1.zodSchemaToTable)(schema)).toBe(expected);
|
|
180
|
+
});
|
|
181
|
+
it('should convert object schema with description to table', () => {
|
|
182
|
+
const schema = zod_1.z.object({
|
|
183
|
+
name: zod_1.z.string().describe('用户名称'),
|
|
184
|
+
age: zod_1.z.number().describe('用户年龄'),
|
|
185
|
+
});
|
|
186
|
+
const expected = `| 字段 | 类型 | 描述 |
|
|
187
|
+
|------|------|------|
|
|
188
|
+
| name | String | 用户名称 |
|
|
189
|
+
| age | Number | 用户年龄 |
|
|
190
|
+
`;
|
|
191
|
+
expect((0, index_1.zodSchemaToTable)(schema)).toBe(expected);
|
|
192
|
+
});
|
|
193
|
+
it('should convert object schema with literal to table', () => {
|
|
194
|
+
const schema = zod_1.z.object({
|
|
195
|
+
status: zod_1.z.literal('active'),
|
|
196
|
+
count: zod_1.z.literal(1),
|
|
197
|
+
});
|
|
198
|
+
const expected = `| 字段 | 类型 | 描述 |
|
|
199
|
+
|------|------|------|
|
|
200
|
+
| status | Literal("active") | - |
|
|
201
|
+
| count | Literal(1) | - |
|
|
202
|
+
`;
|
|
203
|
+
expect((0, index_1.zodSchemaToTable)(schema)).toBe(expected);
|
|
204
|
+
});
|
|
205
|
+
it('should fallback to markdown for non-object schema', () => {
|
|
206
|
+
const schema = zod_1.z.string();
|
|
207
|
+
const expected = `- String
|
|
208
|
+
`;
|
|
209
|
+
expect((0, index_1.zodSchemaToTable)(schema)).toBe(expected);
|
|
210
|
+
});
|
|
211
|
+
});
|