@chnak/zod-to-markdown 1.0.1
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/README.md +177 -0
- package/examples/complex-types.md +152 -0
- package/examples/openai-chat-completion.md +191 -0
- package/examples/openai-chat-schema.ts +64 -0
- package/jest.config.js +5 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +131 -0
- package/lib/index.test.d.ts +1 -0
- package/lib/index.test.js +133 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# zod-to-markdown
|
|
2
|
+
|
|
3
|
+
将 Zod schema 转换为 Markdown 文档的工具函数。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @chnak/zod-to-markdown
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 使用方法
|
|
12
|
+
|
|
13
|
+
### ESM / TypeScript
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { zodSchemaToMarkdown } from '@chnak/zod-to-markdown';
|
|
17
|
+
import { z } from 'zod';
|
|
18
|
+
|
|
19
|
+
const schema = z.object({
|
|
20
|
+
name: z.string(),
|
|
21
|
+
age: z.number(),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const markdown = zodSchemaToMarkdown(schema);
|
|
25
|
+
console.log(markdown);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### CommonJS / Node.js
|
|
29
|
+
|
|
30
|
+
```javascript
|
|
31
|
+
const { zodSchemaToMarkdown } = require('@chnak/zod-to-markdown');
|
|
32
|
+
const { z } = require('zod');
|
|
33
|
+
|
|
34
|
+
const schema = z.object({
|
|
35
|
+
name: z.string(),
|
|
36
|
+
age: z.number(),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const markdown = zodSchemaToMarkdown(schema);
|
|
40
|
+
console.log(markdown);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 输出结果
|
|
44
|
+
|
|
45
|
+
```markdown
|
|
46
|
+
- name
|
|
47
|
+
- String
|
|
48
|
+
- age
|
|
49
|
+
- Number
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## 支持的 Zod 类型
|
|
53
|
+
|
|
54
|
+
### 基础类型
|
|
55
|
+
- `ZodObject` - 对象 schema,包含嵌套属性
|
|
56
|
+
- `ZodArray` - 数组 schema,包含元素类型
|
|
57
|
+
- `ZodString` - 字符串,可选 minLength/maxLength
|
|
58
|
+
- `ZodNumber` - 数字,可选 minValue/maxValue
|
|
59
|
+
- `ZodBoolean` - 布尔类型
|
|
60
|
+
- `ZodEnum` - 枚举值
|
|
61
|
+
- `ZodBigInt` - BigInt 类型
|
|
62
|
+
- `ZodDate` - Date 类型
|
|
63
|
+
|
|
64
|
+
### 工具类型
|
|
65
|
+
- `ZodOptional` - 可选属性
|
|
66
|
+
- `ZodNullable` - 可为空属性
|
|
67
|
+
- `ZodDefault` - 默认值
|
|
68
|
+
- `ZodEffects` - transform/coerce 效果
|
|
69
|
+
|
|
70
|
+
### 高级类型
|
|
71
|
+
- `ZodUnion` - 联合类型
|
|
72
|
+
- `ZodDiscriminatedUnion` - 带鉴别键的联合类型
|
|
73
|
+
- `ZodIntersection` - 交叉类型
|
|
74
|
+
- `ZodRecord` - Record(字典)类型
|
|
75
|
+
- `ZodTuple` - 元组类型
|
|
76
|
+
|
|
77
|
+
### 特殊类型
|
|
78
|
+
- `ZodLiteral` - 字面量值(如 `"hello"`, `1`, `true`)
|
|
79
|
+
- `ZodNaN` - NaN 类型
|
|
80
|
+
- `ZodNever` - Never 类型
|
|
81
|
+
- `ZodUnknown` - Unknown 类型
|
|
82
|
+
- `ZodVoid` - Void 类型
|
|
83
|
+
|
|
84
|
+
## 示例
|
|
85
|
+
|
|
86
|
+
### 复杂 Schema
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { z } from 'zod';
|
|
90
|
+
|
|
91
|
+
const userSchema = z.object({
|
|
92
|
+
id: z.string().uuid(),
|
|
93
|
+
name: z.string(),
|
|
94
|
+
email: z.string().email(),
|
|
95
|
+
age: z.number().optional(),
|
|
96
|
+
role: z.enum(['admin', 'user', 'guest']),
|
|
97
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
console.log(zodSchemaToMarkdown(userSchema));
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
输出:
|
|
104
|
+
```markdown
|
|
105
|
+
- id
|
|
106
|
+
- String
|
|
107
|
+
- name
|
|
108
|
+
- String
|
|
109
|
+
- email
|
|
110
|
+
- String
|
|
111
|
+
- age
|
|
112
|
+
- Optional
|
|
113
|
+
- Number
|
|
114
|
+
- role
|
|
115
|
+
- Enum: admin, user, guest
|
|
116
|
+
- metadata
|
|
117
|
+
- Optional
|
|
118
|
+
- Record
|
|
119
|
+
Key:
|
|
120
|
+
- String
|
|
121
|
+
Value:
|
|
122
|
+
- Unknown
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 鉴别联合类型 (Discriminated Union)
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
const messageSchema = z.discriminatedUnion('role', [
|
|
129
|
+
z.object({ role: z.literal('user'), content: z.string() }),
|
|
130
|
+
z.object({ role: z.literal('assistant'), content: z.string() }),
|
|
131
|
+
]);
|
|
132
|
+
|
|
133
|
+
console.log(zodSchemaToMarkdown(messageSchema));
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
输出:
|
|
137
|
+
```markdown
|
|
138
|
+
- DiscriminatedUnion (key: role)
|
|
139
|
+
- role
|
|
140
|
+
- Literal: "user"
|
|
141
|
+
- content
|
|
142
|
+
- String
|
|
143
|
+
|
|
|
144
|
+
- role
|
|
145
|
+
- Literal: "assistant"
|
|
146
|
+
- content
|
|
147
|
+
- String
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Transform 效果
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
const transformedSchema = z.string().transform(val => val.length);
|
|
154
|
+
|
|
155
|
+
console.log(zodSchemaToMarkdown(transformedSchema));
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
输出:
|
|
159
|
+
```markdown
|
|
160
|
+
- Effects (transform)
|
|
161
|
+
- String
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## API
|
|
165
|
+
|
|
166
|
+
### `zodSchemaToMarkdown(schema, indentLevel?)`
|
|
167
|
+
|
|
168
|
+
| 参数 | 类型 | 说明 |
|
|
169
|
+
|------|------|------|
|
|
170
|
+
| `schema` | `z.ZodTypeAny` | 要转换的 Zod schema |
|
|
171
|
+
| `indentLevel` | `number` | 初始缩进级别(默认: `0`) |
|
|
172
|
+
|
|
173
|
+
返回转换后的 Markdown 字符串。
|
|
174
|
+
|
|
175
|
+
## License
|
|
176
|
+
|
|
177
|
+
MIT License
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Zod to Markdown - Complex Types Examples
|
|
2
|
+
|
|
3
|
+
This document demonstrates the `zodSchemaToMarkdown` function's support for complex Zod types used in OpenAI API schemas.
|
|
4
|
+
|
|
5
|
+
## ZodEffects (Transform)
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
const schema = z.string().transform(val => val.length);
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Output:
|
|
12
|
+
```markdown
|
|
13
|
+
- Effects (transform)
|
|
14
|
+
- String
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## ZodDiscriminatedUnion
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
const schema = z.discriminatedUnion('type', [
|
|
21
|
+
z.object({ type: z.literal('a'), a: z.string() }),
|
|
22
|
+
z.object({ type: z.literal('b'), b: z.number() })
|
|
23
|
+
]);
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Output:
|
|
27
|
+
```markdown
|
|
28
|
+
- DiscriminatedUnion (key: type)
|
|
29
|
+
- type
|
|
30
|
+
- Literal: "a"
|
|
31
|
+
- a
|
|
32
|
+
- String
|
|
33
|
+
|
|
|
34
|
+
- type
|
|
35
|
+
- Literal: "b"
|
|
36
|
+
- b
|
|
37
|
+
- Number
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## ZodIntersection
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
const schema = z.object({ a: z.string() }).and(z.object({ b: z.number() }));
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Output:
|
|
47
|
+
```markdown
|
|
48
|
+
- Intersection
|
|
49
|
+
Left:
|
|
50
|
+
- a
|
|
51
|
+
- String
|
|
52
|
+
Right:
|
|
53
|
+
- b
|
|
54
|
+
- Number
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## ZodRecord
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
const schema = z.record(z.string(), z.number());
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Output:
|
|
64
|
+
```markdown
|
|
65
|
+
- Record
|
|
66
|
+
Key:
|
|
67
|
+
- String
|
|
68
|
+
Value:
|
|
69
|
+
- Number
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## ZodTuple
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
const schema = z.tuple([z.string(), z.number()]);
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Output:
|
|
79
|
+
```markdown
|
|
80
|
+
- Tuple
|
|
81
|
+
[0]:
|
|
82
|
+
- String
|
|
83
|
+
[1]:
|
|
84
|
+
- Number
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## ZodLiteral
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
const schema = z.literal('hello');
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Output:
|
|
94
|
+
```markdown
|
|
95
|
+
- Literal: "hello"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Primitive Types
|
|
99
|
+
|
|
100
|
+
### ZodBigInt
|
|
101
|
+
```typescript
|
|
102
|
+
z.bigint()
|
|
103
|
+
```
|
|
104
|
+
Output:
|
|
105
|
+
```markdown
|
|
106
|
+
- BigInt
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### ZodDate
|
|
110
|
+
```typescript
|
|
111
|
+
z.date()
|
|
112
|
+
```
|
|
113
|
+
Output:
|
|
114
|
+
```markdown
|
|
115
|
+
- Date
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### ZodNaN
|
|
119
|
+
```typescript
|
|
120
|
+
z.nan()
|
|
121
|
+
```
|
|
122
|
+
Output:
|
|
123
|
+
```markdown
|
|
124
|
+
- NaN
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### ZodNever
|
|
128
|
+
```typescript
|
|
129
|
+
z.never()
|
|
130
|
+
```
|
|
131
|
+
Output:
|
|
132
|
+
```markdown
|
|
133
|
+
- Never
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### ZodUnknown
|
|
137
|
+
```typescript
|
|
138
|
+
z.unknown()
|
|
139
|
+
```
|
|
140
|
+
Output:
|
|
141
|
+
```markdown
|
|
142
|
+
- Unknown
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### ZodVoid
|
|
146
|
+
```typescript
|
|
147
|
+
z.void()
|
|
148
|
+
```
|
|
149
|
+
Output:
|
|
150
|
+
```markdown
|
|
151
|
+
- Void
|
|
152
|
+
```
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# OpenAI Chat Completion Schema
|
|
2
|
+
|
|
3
|
+
完整的 OpenAI API Schema 转换为 Markdown 文档的示例。
|
|
4
|
+
|
|
5
|
+
## TypeScript 定义
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
const messageSchema = z.discriminatedUnion('role', [
|
|
9
|
+
z.object({
|
|
10
|
+
role: z.literal('system'),
|
|
11
|
+
content: z.string(),
|
|
12
|
+
name: z.string().optional(),
|
|
13
|
+
}),
|
|
14
|
+
z.object({
|
|
15
|
+
role: z.literal('user'),
|
|
16
|
+
content: z.union([z.string(), z.array(z.object({
|
|
17
|
+
type: z.literal('text'),
|
|
18
|
+
text: z.string(),
|
|
19
|
+
}))]),
|
|
20
|
+
name: z.string().optional(),
|
|
21
|
+
}),
|
|
22
|
+
z.object({
|
|
23
|
+
role: z.literal('assistant'),
|
|
24
|
+
content: z.string().nullable(),
|
|
25
|
+
tool_calls: z.array(z.object({
|
|
26
|
+
id: z.string(),
|
|
27
|
+
type: z.literal('function'),
|
|
28
|
+
function: z.object({
|
|
29
|
+
name: z.string(),
|
|
30
|
+
arguments: z.string(),
|
|
31
|
+
}),
|
|
32
|
+
})).optional(),
|
|
33
|
+
name: z.string().optional(),
|
|
34
|
+
}),
|
|
35
|
+
z.object({
|
|
36
|
+
role: z.literal('tool'),
|
|
37
|
+
content: z.union([z.string(), z.object({
|
|
38
|
+
type: z.literal('image_url'),
|
|
39
|
+
image_url: z.object({
|
|
40
|
+
url: z.string(),
|
|
41
|
+
detail: z.enum(['low', 'high', 'auto']).optional(),
|
|
42
|
+
}),
|
|
43
|
+
})]),
|
|
44
|
+
tool_call_id: z.string(),
|
|
45
|
+
name: z.string().optional(),
|
|
46
|
+
}),
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
const chatCompletionRequestSchema = z.object({
|
|
50
|
+
model: z.string(),
|
|
51
|
+
messages: z.array(messageSchema),
|
|
52
|
+
temperature: z.number().min(0).max(2).optional(),
|
|
53
|
+
top_p: z.number().min(0).max(1).optional(),
|
|
54
|
+
n: z.number().int().min(1).optional(),
|
|
55
|
+
stream: z.boolean().optional(),
|
|
56
|
+
stop: z.union([z.string(), z.array(z.string())]).optional(),
|
|
57
|
+
max_tokens: z.number().int().optional(),
|
|
58
|
+
presence_penalty: z.number().min(-2).max(2).optional(),
|
|
59
|
+
frequency_penalty: z.number().min(-2).max(2).optional(),
|
|
60
|
+
logit_bias: z.record(z.string(), z.number()).optional(),
|
|
61
|
+
user: z.string().optional(),
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## 生成的 Markdown 文档
|
|
66
|
+
|
|
67
|
+
```markdown
|
|
68
|
+
- model
|
|
69
|
+
- String
|
|
70
|
+
- messages
|
|
71
|
+
- Array
|
|
72
|
+
- DiscriminatedUnion (key: role)
|
|
73
|
+
- role
|
|
74
|
+
- Literal: "system"
|
|
75
|
+
- content
|
|
76
|
+
- String
|
|
77
|
+
- name
|
|
78
|
+
- Optional
|
|
79
|
+
- String
|
|
80
|
+
|
|
|
81
|
+
- role
|
|
82
|
+
- Literal: "user"
|
|
83
|
+
- content
|
|
84
|
+
- Union
|
|
85
|
+
- String
|
|
86
|
+
|
|
|
87
|
+
- Array
|
|
88
|
+
- type
|
|
89
|
+
- Literal: "text"
|
|
90
|
+
- text
|
|
91
|
+
- String
|
|
92
|
+
- name
|
|
93
|
+
- Optional
|
|
94
|
+
- String
|
|
95
|
+
|
|
|
96
|
+
- role
|
|
97
|
+
- Literal: "assistant"
|
|
98
|
+
- content
|
|
99
|
+
- Nullable
|
|
100
|
+
- String
|
|
101
|
+
- tool_calls
|
|
102
|
+
- Optional
|
|
103
|
+
- Array
|
|
104
|
+
- id
|
|
105
|
+
- String
|
|
106
|
+
- type
|
|
107
|
+
- Literal: "function"
|
|
108
|
+
- function
|
|
109
|
+
- name
|
|
110
|
+
- String
|
|
111
|
+
- arguments
|
|
112
|
+
- String
|
|
113
|
+
- name
|
|
114
|
+
- Optional
|
|
115
|
+
- String
|
|
116
|
+
|
|
|
117
|
+
- role
|
|
118
|
+
- Literal: "tool"
|
|
119
|
+
- content
|
|
120
|
+
- Union
|
|
121
|
+
- String
|
|
122
|
+
|
|
|
123
|
+
- type
|
|
124
|
+
- Literal: "image_url"
|
|
125
|
+
- image_url
|
|
126
|
+
- url
|
|
127
|
+
- String
|
|
128
|
+
- detail
|
|
129
|
+
- Optional
|
|
130
|
+
- Enum: low, high, auto
|
|
131
|
+
- tool_call_id
|
|
132
|
+
- String
|
|
133
|
+
- name
|
|
134
|
+
- Optional
|
|
135
|
+
- String
|
|
136
|
+
- temperature
|
|
137
|
+
- Optional
|
|
138
|
+
- Number (minValue: 0) (maxValue: 2)
|
|
139
|
+
- top_p
|
|
140
|
+
- Optional
|
|
141
|
+
- Number (minValue: 0) (maxValue: 1)
|
|
142
|
+
- n
|
|
143
|
+
- Optional
|
|
144
|
+
- Number (minValue: 1)
|
|
145
|
+
- stream
|
|
146
|
+
- Optional
|
|
147
|
+
- Boolean
|
|
148
|
+
- stop
|
|
149
|
+
- Optional
|
|
150
|
+
- Union
|
|
151
|
+
- String
|
|
152
|
+
|
|
|
153
|
+
- Array
|
|
154
|
+
- String
|
|
155
|
+
- max_tokens
|
|
156
|
+
- Optional
|
|
157
|
+
- Number
|
|
158
|
+
- presence_penalty
|
|
159
|
+
- Optional
|
|
160
|
+
- Number (minValue: -2) (maxValue: 2)
|
|
161
|
+
- frequency_penalty
|
|
162
|
+
- Optional
|
|
163
|
+
- Number (minValue: -2) (maxValue: 2)
|
|
164
|
+
- logit_bias
|
|
165
|
+
- Optional
|
|
166
|
+
- Record
|
|
167
|
+
Key:
|
|
168
|
+
- String
|
|
169
|
+
Value:
|
|
170
|
+
- Number
|
|
171
|
+
- user
|
|
172
|
+
- Optional
|
|
173
|
+
- String
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## 使用的类型覆盖
|
|
177
|
+
|
|
178
|
+
| 类型 | 出现位置 |
|
|
179
|
+
|------|----------|
|
|
180
|
+
| `ZodDiscriminatedUnion` | `messages` 数组元素,role 鉴别键 |
|
|
181
|
+
| `ZodObject` | 顶层 schema 和各 message 类型 |
|
|
182
|
+
| `ZodArray` | `messages`, `tool_calls`, `stop` |
|
|
183
|
+
| `ZodOptional` | `name`, `tool_calls`, `detail` 等 |
|
|
184
|
+
| `ZodNullable` | `content` (assistant) |
|
|
185
|
+
| `ZodUnion` | `content`, `stop` |
|
|
186
|
+
| `ZodLiteral` | `role` 值,`type` 值 |
|
|
187
|
+
| `ZodEnum` | `detail` 枚举 |
|
|
188
|
+
| `ZodRecord` | `logit_bias` |
|
|
189
|
+
| `ZodString` | 各种字符串字段 |
|
|
190
|
+
| `ZodNumber` | 各种数字字段,带 min/max 约束 |
|
|
191
|
+
| `ZodBoolean` | `stream` |
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { zodSchemaToMarkdown } from '../src/index';
|
|
3
|
+
|
|
4
|
+
// OpenAI Chat Message Schema Example
|
|
5
|
+
const messageSchema = z.discriminatedUnion('role', [
|
|
6
|
+
z.object({
|
|
7
|
+
role: z.literal('system'),
|
|
8
|
+
content: z.string(),
|
|
9
|
+
name: z.string().optional(),
|
|
10
|
+
}),
|
|
11
|
+
z.object({
|
|
12
|
+
role: z.literal('user'),
|
|
13
|
+
content: z.union([z.string(), z.array(z.object({
|
|
14
|
+
type: z.literal('text'),
|
|
15
|
+
text: z.string(),
|
|
16
|
+
}))]),
|
|
17
|
+
name: z.string().optional(),
|
|
18
|
+
}),
|
|
19
|
+
z.object({
|
|
20
|
+
role: z.literal('assistant'),
|
|
21
|
+
content: z.string().nullable(),
|
|
22
|
+
tool_calls: z.array(z.object({
|
|
23
|
+
id: z.string(),
|
|
24
|
+
type: z.literal('function'),
|
|
25
|
+
function: z.object({
|
|
26
|
+
name: z.string(),
|
|
27
|
+
arguments: z.string(),
|
|
28
|
+
}),
|
|
29
|
+
})).optional(),
|
|
30
|
+
name: z.string().optional(),
|
|
31
|
+
}),
|
|
32
|
+
z.object({
|
|
33
|
+
role: z.literal('tool'),
|
|
34
|
+
content: z.union([z.string(), z.object({
|
|
35
|
+
type: z.literal('image_url'),
|
|
36
|
+
image_url: z.object({
|
|
37
|
+
url: z.string(),
|
|
38
|
+
detail: z.enum(['low', 'high', 'auto']).optional(),
|
|
39
|
+
}),
|
|
40
|
+
})]),
|
|
41
|
+
tool_call_id: z.string(),
|
|
42
|
+
name: z.string().optional(),
|
|
43
|
+
}),
|
|
44
|
+
]);
|
|
45
|
+
|
|
46
|
+
const chatCompletionRequestSchema = z.object({
|
|
47
|
+
model: z.string(),
|
|
48
|
+
messages: z.array(messageSchema),
|
|
49
|
+
temperature: z.number().min(0).max(2).optional(),
|
|
50
|
+
top_p: z.number().min(0).max(1).optional(),
|
|
51
|
+
n: z.number().int().min(1).optional(),
|
|
52
|
+
stream: z.boolean().optional(),
|
|
53
|
+
stop: z.union([z.string(), z.array(z.string())]).optional(),
|
|
54
|
+
max_tokens: z.number().int().optional(),
|
|
55
|
+
presence_penalty: z.number().min(-2).max(2).optional(),
|
|
56
|
+
frequency_penalty: z.number().min(-2).max(2).optional(),
|
|
57
|
+
logit_bias: z.record(z.string(), z.number()).optional(),
|
|
58
|
+
user: z.string().optional(),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const schema = chatCompletionRequestSchema;
|
|
62
|
+
const markdown = zodSchemaToMarkdown(schema);
|
|
63
|
+
|
|
64
|
+
console.log(markdown);
|
package/jest.config.js
ADDED
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.zodSchemaToMarkdown = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
function zodSchemaToMarkdown(schema, indentLevel = 0) {
|
|
6
|
+
let markdown = "";
|
|
7
|
+
const indent = " ".repeat(indentLevel);
|
|
8
|
+
if (schema instanceof zod_1.z.ZodObject) {
|
|
9
|
+
const shape = schema.shape;
|
|
10
|
+
Object.keys(shape).forEach((key) => {
|
|
11
|
+
const subSchema = shape[key];
|
|
12
|
+
const description = subSchema.description ? `: ${subSchema.description}` : "";
|
|
13
|
+
markdown += `${indent}- ${key}${description}\n`;
|
|
14
|
+
markdown += zodSchemaToMarkdown(subSchema, indentLevel + 1);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
else if (schema instanceof zod_1.z.ZodArray) {
|
|
18
|
+
markdown += `${indent}- Array\n`;
|
|
19
|
+
markdown += zodSchemaToMarkdown(schema.element, indentLevel + 1);
|
|
20
|
+
}
|
|
21
|
+
else if (schema instanceof zod_1.z.ZodString) {
|
|
22
|
+
markdown += `${indent}- String`;
|
|
23
|
+
if (schema.minLength !== null) {
|
|
24
|
+
markdown += ` (minLength: ${schema.minLength})`;
|
|
25
|
+
}
|
|
26
|
+
if (schema.maxLength !== null) {
|
|
27
|
+
markdown += ` (maxLength: ${schema.maxLength})`;
|
|
28
|
+
}
|
|
29
|
+
markdown += "\n";
|
|
30
|
+
}
|
|
31
|
+
else if (schema instanceof zod_1.z.ZodNumber) {
|
|
32
|
+
markdown += `${indent}- Number`;
|
|
33
|
+
if (schema.minValue !== null) {
|
|
34
|
+
markdown += ` (minValue: ${schema.minValue})`;
|
|
35
|
+
}
|
|
36
|
+
if (schema.maxValue !== null) {
|
|
37
|
+
markdown += ` (maxValue: ${schema.maxValue})`;
|
|
38
|
+
}
|
|
39
|
+
markdown += "\n";
|
|
40
|
+
}
|
|
41
|
+
else if (schema instanceof zod_1.z.ZodEnum) {
|
|
42
|
+
const values = schema.options.join(", ");
|
|
43
|
+
markdown += `${indent}- Enum: ${values}\n`;
|
|
44
|
+
}
|
|
45
|
+
else if (schema instanceof zod_1.z.ZodUnion) {
|
|
46
|
+
markdown += `${indent}- Union\n`;
|
|
47
|
+
schema.options.forEach((option, index) => {
|
|
48
|
+
markdown += zodSchemaToMarkdown(option, indentLevel + 1);
|
|
49
|
+
if (index < schema.options.length - 1) {
|
|
50
|
+
markdown += `${indent} |\n`;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
else if (schema instanceof zod_1.z.ZodBoolean) {
|
|
55
|
+
markdown += `${indent}- Boolean\n`;
|
|
56
|
+
}
|
|
57
|
+
else if (schema instanceof zod_1.z.ZodDefault) {
|
|
58
|
+
markdown += `${indent}- Default: ${JSON.stringify(schema._def.defaultValue())}\n`;
|
|
59
|
+
markdown += zodSchemaToMarkdown(schema.removeDefault(), indentLevel);
|
|
60
|
+
}
|
|
61
|
+
else if (schema instanceof zod_1.z.ZodOptional) {
|
|
62
|
+
markdown += `${indent}- Optional\n`;
|
|
63
|
+
markdown += zodSchemaToMarkdown(schema.unwrap(), indentLevel + 1);
|
|
64
|
+
}
|
|
65
|
+
else if (schema instanceof zod_1.z.ZodNullable) {
|
|
66
|
+
markdown += `${indent}- Nullable\n`;
|
|
67
|
+
markdown += zodSchemaToMarkdown(schema.unwrap(), indentLevel + 1);
|
|
68
|
+
}
|
|
69
|
+
else if (schema instanceof zod_1.z.ZodEffects) {
|
|
70
|
+
const effectType = schema._def.effect.type;
|
|
71
|
+
markdown += `${indent}- Effects (${effectType})\n`;
|
|
72
|
+
markdown += zodSchemaToMarkdown(schema.innerType(), indentLevel + 1);
|
|
73
|
+
}
|
|
74
|
+
else if (schema instanceof zod_1.z.ZodDiscriminatedUnion) {
|
|
75
|
+
const discriminator = schema.discriminator;
|
|
76
|
+
markdown += `${indent}- DiscriminatedUnion (key: ${discriminator})\n`;
|
|
77
|
+
schema.options.forEach((option, index) => {
|
|
78
|
+
markdown += zodSchemaToMarkdown(option, indentLevel + 1);
|
|
79
|
+
if (index < schema.options.length - 1) {
|
|
80
|
+
markdown += `${indent} |\n`;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
else if (schema instanceof zod_1.z.ZodIntersection) {
|
|
85
|
+
markdown += `${indent}- Intersection\n`;
|
|
86
|
+
markdown += `${indent} Left:\n`;
|
|
87
|
+
markdown += zodSchemaToMarkdown(schema._def.left, indentLevel + 2);
|
|
88
|
+
markdown += `${indent} Right:\n`;
|
|
89
|
+
markdown += zodSchemaToMarkdown(schema._def.right, indentLevel + 2);
|
|
90
|
+
}
|
|
91
|
+
else if (schema instanceof zod_1.z.ZodRecord) {
|
|
92
|
+
markdown += `${indent}- Record\n`;
|
|
93
|
+
markdown += `${indent} Key:\n`;
|
|
94
|
+
markdown += zodSchemaToMarkdown(schema.keySchema, indentLevel + 2);
|
|
95
|
+
markdown += `${indent} Value:\n`;
|
|
96
|
+
markdown += zodSchemaToMarkdown(schema.valueSchema, indentLevel + 2);
|
|
97
|
+
}
|
|
98
|
+
else if (schema instanceof zod_1.z.ZodTuple) {
|
|
99
|
+
markdown += `${indent}- Tuple\n`;
|
|
100
|
+
schema.items.forEach((item, index) => {
|
|
101
|
+
markdown += `${indent} [${index}]:\n`;
|
|
102
|
+
markdown += zodSchemaToMarkdown(item, indentLevel + 2);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
else if (schema instanceof zod_1.z.ZodLiteral) {
|
|
106
|
+
markdown += `${indent}- Literal: ${JSON.stringify(schema.value)}\n`;
|
|
107
|
+
}
|
|
108
|
+
else if (schema instanceof zod_1.z.ZodBigInt) {
|
|
109
|
+
markdown += `${indent}- BigInt\n`;
|
|
110
|
+
}
|
|
111
|
+
else if (schema instanceof zod_1.z.ZodDate) {
|
|
112
|
+
markdown += `${indent}- Date\n`;
|
|
113
|
+
}
|
|
114
|
+
else if (schema instanceof zod_1.z.ZodNaN) {
|
|
115
|
+
markdown += `${indent}- NaN\n`;
|
|
116
|
+
}
|
|
117
|
+
else if (schema instanceof zod_1.z.ZodNever) {
|
|
118
|
+
markdown += `${indent}- Never\n`;
|
|
119
|
+
}
|
|
120
|
+
else if (schema instanceof zod_1.z.ZodUnknown) {
|
|
121
|
+
markdown += `${indent}- Unknown\n`;
|
|
122
|
+
}
|
|
123
|
+
else if (schema instanceof zod_1.z.ZodVoid) {
|
|
124
|
+
markdown += `${indent}- Void\n`;
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
markdown += `${indent}- Type: ${schema.constructor.name}\n`;
|
|
128
|
+
}
|
|
129
|
+
return markdown;
|
|
130
|
+
}
|
|
131
|
+
exports.zodSchemaToMarkdown = zodSchemaToMarkdown;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const zod_1 = require("zod");
|
|
4
|
+
const index_1 = require("./index");
|
|
5
|
+
describe('zodSchemaToMarkdown', () => {
|
|
6
|
+
it('should convert a simple object schema to markdown', () => {
|
|
7
|
+
const schema = zod_1.z.object({
|
|
8
|
+
name: zod_1.z.string(),
|
|
9
|
+
age: zod_1.z.number(),
|
|
10
|
+
});
|
|
11
|
+
const expected = `- name
|
|
12
|
+
- String
|
|
13
|
+
- age
|
|
14
|
+
- Number
|
|
15
|
+
`;
|
|
16
|
+
expect((0, index_1.zodSchemaToMarkdown)(schema)).toBe(expected);
|
|
17
|
+
});
|
|
18
|
+
it('should convert an array schema to markdown', () => {
|
|
19
|
+
const schema = zod_1.z.array(zod_1.z.string());
|
|
20
|
+
const expected = `- Array
|
|
21
|
+
- String
|
|
22
|
+
`;
|
|
23
|
+
expect((0, index_1.zodSchemaToMarkdown)(schema)).toBe(expected);
|
|
24
|
+
});
|
|
25
|
+
it('should convert a union schema to markdown', () => {
|
|
26
|
+
const schema = zod_1.z.union([zod_1.z.string(), zod_1.z.number()]);
|
|
27
|
+
const expected = `- Union
|
|
28
|
+
- String
|
|
29
|
+
|
|
|
30
|
+
- Number
|
|
31
|
+
`;
|
|
32
|
+
expect((0, index_1.zodSchemaToMarkdown)(schema)).toBe(expected);
|
|
33
|
+
});
|
|
34
|
+
it('should convert ZodEffects (transform) to markdown', () => {
|
|
35
|
+
const schema = zod_1.z.string().transform(val => val.length);
|
|
36
|
+
const expected = `- Effects (transform)
|
|
37
|
+
- String
|
|
38
|
+
`;
|
|
39
|
+
expect((0, index_1.zodSchemaToMarkdown)(schema)).toBe(expected);
|
|
40
|
+
});
|
|
41
|
+
it('should convert ZodDiscriminatedUnion to markdown', () => {
|
|
42
|
+
const schema = zod_1.z.discriminatedUnion('type', [
|
|
43
|
+
zod_1.z.object({ type: zod_1.z.literal('a'), a: zod_1.z.string() }),
|
|
44
|
+
zod_1.z.object({ type: zod_1.z.literal('b'), b: zod_1.z.number() })
|
|
45
|
+
]);
|
|
46
|
+
const expected = `- DiscriminatedUnion (key: type)
|
|
47
|
+
- type
|
|
48
|
+
- Literal: "a"
|
|
49
|
+
- a
|
|
50
|
+
- String
|
|
51
|
+
|
|
|
52
|
+
- type
|
|
53
|
+
- Literal: "b"
|
|
54
|
+
- b
|
|
55
|
+
- Number
|
|
56
|
+
`;
|
|
57
|
+
expect((0, index_1.zodSchemaToMarkdown)(schema)).toBe(expected);
|
|
58
|
+
});
|
|
59
|
+
it('should convert ZodIntersection to markdown', () => {
|
|
60
|
+
const schema = zod_1.z.object({ a: zod_1.z.string() }).and(zod_1.z.object({ b: zod_1.z.number() }));
|
|
61
|
+
const expected = `- Intersection
|
|
62
|
+
Left:
|
|
63
|
+
- a
|
|
64
|
+
- String
|
|
65
|
+
Right:
|
|
66
|
+
- b
|
|
67
|
+
- Number
|
|
68
|
+
`;
|
|
69
|
+
expect((0, index_1.zodSchemaToMarkdown)(schema)).toBe(expected);
|
|
70
|
+
});
|
|
71
|
+
it('should convert ZodRecord to markdown', () => {
|
|
72
|
+
const schema = zod_1.z.record(zod_1.z.string(), zod_1.z.number());
|
|
73
|
+
const expected = `- Record
|
|
74
|
+
Key:
|
|
75
|
+
- String
|
|
76
|
+
Value:
|
|
77
|
+
- Number
|
|
78
|
+
`;
|
|
79
|
+
expect((0, index_1.zodSchemaToMarkdown)(schema)).toBe(expected);
|
|
80
|
+
});
|
|
81
|
+
it('should convert ZodTuple to markdown', () => {
|
|
82
|
+
const schema = zod_1.z.tuple([zod_1.z.string(), zod_1.z.number()]);
|
|
83
|
+
const expected = `- Tuple
|
|
84
|
+
[0]:
|
|
85
|
+
- String
|
|
86
|
+
[1]:
|
|
87
|
+
- Number
|
|
88
|
+
`;
|
|
89
|
+
expect((0, index_1.zodSchemaToMarkdown)(schema)).toBe(expected);
|
|
90
|
+
});
|
|
91
|
+
it('should convert ZodLiteral to markdown', () => {
|
|
92
|
+
const schema = zod_1.z.literal('hello');
|
|
93
|
+
const expected = `- Literal: "hello"
|
|
94
|
+
`;
|
|
95
|
+
expect((0, index_1.zodSchemaToMarkdown)(schema)).toBe(expected);
|
|
96
|
+
});
|
|
97
|
+
it('should convert ZodBigInt to markdown', () => {
|
|
98
|
+
const schema = zod_1.z.bigint();
|
|
99
|
+
const expected = `- BigInt
|
|
100
|
+
`;
|
|
101
|
+
expect((0, index_1.zodSchemaToMarkdown)(schema)).toBe(expected);
|
|
102
|
+
});
|
|
103
|
+
it('should convert ZodDate to markdown', () => {
|
|
104
|
+
const schema = zod_1.z.date();
|
|
105
|
+
const expected = `- Date
|
|
106
|
+
`;
|
|
107
|
+
expect((0, index_1.zodSchemaToMarkdown)(schema)).toBe(expected);
|
|
108
|
+
});
|
|
109
|
+
it('should convert ZodNaN to markdown', () => {
|
|
110
|
+
const schema = zod_1.z.nan();
|
|
111
|
+
const expected = `- NaN
|
|
112
|
+
`;
|
|
113
|
+
expect((0, index_1.zodSchemaToMarkdown)(schema)).toBe(expected);
|
|
114
|
+
});
|
|
115
|
+
it('should convert ZodNever to markdown', () => {
|
|
116
|
+
const schema = zod_1.z.never();
|
|
117
|
+
const expected = `- Never
|
|
118
|
+
`;
|
|
119
|
+
expect((0, index_1.zodSchemaToMarkdown)(schema)).toBe(expected);
|
|
120
|
+
});
|
|
121
|
+
it('should convert ZodUnknown to markdown', () => {
|
|
122
|
+
const schema = zod_1.z.unknown();
|
|
123
|
+
const expected = `- Unknown
|
|
124
|
+
`;
|
|
125
|
+
expect((0, index_1.zodSchemaToMarkdown)(schema)).toBe(expected);
|
|
126
|
+
});
|
|
127
|
+
it('should convert ZodVoid to markdown', () => {
|
|
128
|
+
const schema = zod_1.z.void();
|
|
129
|
+
const expected = `- Void
|
|
130
|
+
`;
|
|
131
|
+
expect((0, index_1.zodSchemaToMarkdown)(schema)).toBe(expected);
|
|
132
|
+
});
|
|
133
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@chnak/zod-to-markdown",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "A utility function to convert Zod schemas to Markdown documentation",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"types": "lib/index.d.ts",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"test": "jest",
|
|
13
|
+
"prepublish": "npm run build"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"zod",
|
|
17
|
+
"markdown",
|
|
18
|
+
"documentation",
|
|
19
|
+
"schema",
|
|
20
|
+
"typescript"
|
|
21
|
+
],
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/chnak/zod-to-markdown.git"
|
|
26
|
+
},
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/chnak/zod-to-markdown/issues"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://github.com/chnak/zod-to-markdown#readme",
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"zod": "^3.24.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/jest": "^29.5.12",
|
|
36
|
+
"@types/node": "^14.0.0",
|
|
37
|
+
"jest": "^29.7.0",
|
|
38
|
+
"ts-jest": "^29.1.2",
|
|
39
|
+
"typescript": "^4.0.0"
|
|
40
|
+
}
|
|
41
|
+
}
|