schema-dsl 1.2.5 → 2.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.
Files changed (243) hide show
  1. package/CHANGELOG.md +130 -238
  2. package/LICENSE +21 -21
  3. package/README.md +628 -2486
  4. package/dist/DslBuilder-BIgQOAXp.d.ts +343 -0
  5. package/dist/DslBuilder-CjHTucNQ.d.cts +343 -0
  6. package/dist/Validator-CllRdrY0.d.ts +192 -0
  7. package/dist/Validator-D6okG9tr.d.cts +192 -0
  8. package/dist/index.cjs +6640 -0
  9. package/dist/index.d.cts +1151 -0
  10. package/dist/index.d.ts +1151 -0
  11. package/dist/index.js +6574 -0
  12. package/dist/plugin-CIKtTMtS.d.cts +246 -0
  13. package/dist/plugin-CIKtTMtS.d.ts +246 -0
  14. package/dist/plugins/custom-format.cjs +3818 -0
  15. package/dist/plugins/custom-format.d.cts +12 -0
  16. package/dist/plugins/custom-format.d.ts +12 -0
  17. package/dist/plugins/custom-format.js +3788 -0
  18. package/dist/plugins/custom-type-example.cjs +3811 -0
  19. package/dist/plugins/custom-type-example.d.cts +8 -0
  20. package/dist/plugins/custom-type-example.d.ts +8 -0
  21. package/dist/plugins/custom-type-example.js +3781 -0
  22. package/dist/plugins/custom-validator.cjs +144 -0
  23. package/dist/plugins/custom-validator.d.cts +10 -0
  24. package/dist/plugins/custom-validator.d.ts +10 -0
  25. package/dist/plugins/custom-validator.js +119 -0
  26. package/docs/FEATURE-INDEX.md +553 -519
  27. package/docs/add-custom-locale.md +496 -483
  28. package/docs/add-keyword.md +24 -0
  29. package/docs/api-reference.md +1047 -805
  30. package/docs/api.md +13 -0
  31. package/docs/best-practices-project-structure.md +417 -408
  32. package/docs/best-practices.md +712 -672
  33. package/docs/cache-manager.md +344 -336
  34. package/docs/compile.md +45 -0
  35. package/docs/conditional-api.md +1307 -1278
  36. package/docs/custom-extensions-guide.md +339 -411
  37. package/docs/design-philosophy.md +606 -601
  38. package/docs/doc-index.md +324 -0
  39. package/docs/dsl-syntax.md +714 -664
  40. package/docs/dynamic-locale.md +608 -598
  41. package/docs/enum.md +482 -475
  42. package/docs/error-handling.md +1975 -1966
  43. package/docs/export-guide.md +501 -462
  44. package/docs/export-limitations.md +567 -551
  45. package/docs/faq.md +596 -577
  46. package/docs/frontend-i18n-guide.md +307 -293
  47. package/docs/i18n-user-guide.md +487 -474
  48. package/docs/i18n.md +476 -457
  49. package/docs/index.md +48 -0
  50. package/docs/json-schema-basics.md +40 -0
  51. package/docs/label-vs-description.md +271 -262
  52. package/docs/markdown-exporter.md +406 -397
  53. package/docs/mongodb-exporter.md +302 -295
  54. package/docs/multi-language.md +26 -0
  55. package/docs/multi-type-support.md +322 -329
  56. package/docs/mysql-exporter.md +280 -273
  57. package/docs/number-operators.md +449 -442
  58. package/docs/optional-marker-guide.md +326 -321
  59. package/docs/performance-guide.md +49 -0
  60. package/docs/plugin-system.md +381 -542
  61. package/docs/plugin-type-registration.md +34 -0
  62. package/docs/postgresql-exporter.md +311 -304
  63. package/docs/public/favicon.svg +5 -0
  64. package/docs/quick-start.md +435 -761
  65. package/docs/runtime-locale-support.md +532 -521
  66. package/docs/schema-helper.md +345 -340
  67. package/docs/schema-utils-advanced-issues.md +23 -0
  68. package/docs/schema-utils-best-practices.md +20 -0
  69. package/docs/schema-utils-chaining.md +150 -143
  70. package/docs/schema-utils.md +524 -490
  71. package/docs/security-checklist.md +20 -0
  72. package/docs/string-extensions.md +488 -480
  73. package/docs/troubleshooting.md +486 -471
  74. package/docs/type-converter.md +310 -319
  75. package/docs/type-reference.md +242 -219
  76. package/docs/typescript-guide.md +584 -573
  77. package/docs/union-type-guide.md +157 -147
  78. package/docs/union-types.md +284 -277
  79. package/docs/validate-async.md +491 -480
  80. package/docs/validate-batch.md +49 -0
  81. package/docs/validate-dsl-object-support.md +578 -573
  82. package/docs/validate.md +506 -486
  83. package/docs/validation-guide.md +502 -484
  84. package/docs/validator.md +39 -0
  85. package/package.json +131 -73
  86. package/plugins/custom-format.cjs +8 -0
  87. package/plugins/custom-type-example.cjs +8 -0
  88. package/plugins/custom-validator.cjs +8 -0
  89. package/src/adapters/DslAdapter.ts +111 -0
  90. package/src/adapters/index.ts +1 -0
  91. package/src/config/constants.ts +83 -0
  92. package/src/config/index.ts +2 -0
  93. package/src/config/patterns.ts +77 -0
  94. package/src/core/CacheManager.ts +169 -0
  95. package/src/core/ConditionalBuilder.ts +382 -0
  96. package/src/core/ConditionalRuntime.ts +28 -0
  97. package/src/core/ConditionalValidator.ts +255 -0
  98. package/src/core/DslBuilder.ts +687 -0
  99. package/src/core/ErrorCodes.ts +38 -0
  100. package/src/core/ErrorFormatter.ts +271 -0
  101. package/src/core/JSONSchemaCore.ts +65 -0
  102. package/src/core/Locale.ts +187 -0
  103. package/src/core/MessageTemplate.ts +42 -0
  104. package/src/core/ObjectDslBuilder.ts +64 -0
  105. package/src/core/PluginManager.ts +326 -0
  106. package/src/core/StringExtensions.ts +140 -0
  107. package/src/core/TemplateEngine.ts +44 -0
  108. package/src/core/Validator.ts +448 -0
  109. package/src/errors/I18nError.ts +159 -0
  110. package/src/errors/ValidationError.ts +105 -0
  111. package/src/exporters/BaseExporter.ts +60 -0
  112. package/src/exporters/MarkdownExporter.ts +305 -0
  113. package/src/exporters/MongoDBExporter.ts +126 -0
  114. package/src/exporters/MySQLExporter.ts +156 -0
  115. package/src/exporters/PostgreSQLExporter.ts +222 -0
  116. package/src/exporters/index.ts +18 -0
  117. package/src/index.ts +651 -0
  118. package/{lib/locales/en-US.js → src/locales/en-US.ts} +160 -176
  119. package/{lib/locales/es-ES.js → src/locales/es-ES.ts} +160 -113
  120. package/{lib/locales/fr-FR.js → src/locales/fr-FR.ts} +160 -113
  121. package/src/locales/index.ts +103 -0
  122. package/{lib/locales/ja-JP.js → src/locales/ja-JP.ts} +160 -118
  123. package/src/locales/types.ts +156 -0
  124. package/{lib/locales/zh-CN.js → src/locales/zh-CN.ts} +160 -177
  125. package/src/parser/ConstraintParser.ts +101 -0
  126. package/src/parser/DslParser.ts +470 -0
  127. package/src/parser/SchemaCompiler.ts +66 -0
  128. package/src/parser/TypeRegistry.ts +250 -0
  129. package/src/parser/index.ts +6 -0
  130. package/src/plugins/custom-format.ts +124 -0
  131. package/src/plugins/custom-type-example.ts +106 -0
  132. package/src/plugins/custom-validator.ts +138 -0
  133. package/src/types/conditional.ts +28 -0
  134. package/src/types/config.ts +59 -0
  135. package/src/types/dsl.ts +131 -0
  136. package/src/types/error.ts +60 -0
  137. package/src/types/index.ts +17 -0
  138. package/src/types/infer.ts +128 -0
  139. package/src/types/plugin.ts +58 -0
  140. package/src/types/safe-regex.d.ts +9 -0
  141. package/src/types/schema.ts +66 -0
  142. package/src/types/validate.ts +71 -0
  143. package/src/utils/SchemaHelper.ts +196 -0
  144. package/src/utils/SchemaUtils.ts +365 -0
  145. package/src/utils/TypeConverter.ts +215 -0
  146. package/src/utils/index.ts +10 -0
  147. package/src/validators/CustomKeywords.ts +477 -0
  148. package/.eslintignore +0 -11
  149. package/.eslintrc.json +0 -27
  150. package/CONTRIBUTING.md +0 -368
  151. package/STATUS.md +0 -491
  152. package/changelogs/v1.0.0.md +0 -328
  153. package/changelogs/v1.0.9.md +0 -367
  154. package/changelogs/v1.1.0.md +0 -389
  155. package/changelogs/v1.1.1.md +0 -308
  156. package/changelogs/v1.1.2.md +0 -183
  157. package/changelogs/v1.1.3.md +0 -161
  158. package/changelogs/v1.1.4.md +0 -432
  159. package/changelogs/v1.1.5.md +0 -493
  160. package/changelogs/v1.1.6.md +0 -211
  161. package/changelogs/v1.1.8.md +0 -376
  162. package/changelogs/v1.2.3.md +0 -124
  163. package/docs/INDEX.md +0 -252
  164. package/docs/issues-resolved-summary.md +0 -196
  165. package/docs/performance-benchmark-report.md +0 -179
  166. package/docs/performance-quick-reference.md +0 -123
  167. package/docs/user-questions-answered.md +0 -353
  168. package/docs/validation-rules-v1.0.2.md +0 -1608
  169. package/examples/README.md +0 -81
  170. package/examples/array-dsl-example.js +0 -227
  171. package/examples/conditional-example.js +0 -288
  172. package/examples/conditional-non-object.js +0 -129
  173. package/examples/conditional-validate-example.js +0 -321
  174. package/examples/custom-extension.js +0 -85
  175. package/examples/dsl-match-example.js +0 -74
  176. package/examples/dsl-style.js +0 -118
  177. package/examples/dynamic-locale-configuration.js +0 -348
  178. package/examples/dynamic-locale-example.js +0 -287
  179. package/examples/enum.examples.js +0 -324
  180. package/examples/export-demo.js +0 -130
  181. package/examples/express-integration.js +0 -376
  182. package/examples/i18n-error-handling-complete.js +0 -381
  183. package/examples/i18n-error-handling-quickstart.md +0 -0
  184. package/examples/i18n-error.examples.js +0 -181
  185. package/examples/i18n-full-demo.js +0 -301
  186. package/examples/i18n-memory-safety.examples.js +0 -268
  187. package/examples/markdown-export.js +0 -71
  188. package/examples/middleware-usage.js +0 -93
  189. package/examples/new-features-comparison.js +0 -315
  190. package/examples/password-reset/README.md +0 -153
  191. package/examples/password-reset/schema.js +0 -26
  192. package/examples/password-reset/test.js +0 -101
  193. package/examples/plugin-system.examples.js +0 -205
  194. package/examples/schema-utils-chaining.examples.js +0 -250
  195. package/examples/simple-example.js +0 -122
  196. package/examples/slug.examples.js +0 -179
  197. package/examples/string-extensions.js +0 -297
  198. package/examples/union-type-example.js +0 -127
  199. package/examples/union-types-example.js +0 -77
  200. package/examples/user-registration/README.md +0 -156
  201. package/examples/user-registration/routes.js +0 -92
  202. package/examples/user-registration/schema.js +0 -150
  203. package/examples/user-registration/server.js +0 -74
  204. package/index.d.ts +0 -3658
  205. package/index.js +0 -475
  206. package/index.mjs +0 -60
  207. package/lib/adapters/DslAdapter.js +0 -995
  208. package/lib/adapters/index.js +0 -20
  209. package/lib/config/constants.js +0 -286
  210. package/lib/config/patterns/common.js +0 -47
  211. package/lib/config/patterns/creditCard.js +0 -9
  212. package/lib/config/patterns/idCard.js +0 -9
  213. package/lib/config/patterns/index.js +0 -9
  214. package/lib/config/patterns/licensePlate.js +0 -4
  215. package/lib/config/patterns/passport.js +0 -4
  216. package/lib/config/patterns/phone.js +0 -9
  217. package/lib/config/patterns/postalCode.js +0 -5
  218. package/lib/core/CacheManager.js +0 -376
  219. package/lib/core/ConditionalBuilder.js +0 -503
  220. package/lib/core/DslBuilder.js +0 -1589
  221. package/lib/core/ErrorCodes.js +0 -233
  222. package/lib/core/ErrorFormatter.js +0 -445
  223. package/lib/core/JSONSchemaCore.js +0 -347
  224. package/lib/core/Locale.js +0 -130
  225. package/lib/core/MessageTemplate.js +0 -98
  226. package/lib/core/PluginManager.js +0 -448
  227. package/lib/core/StringExtensions.js +0 -240
  228. package/lib/core/Validator.js +0 -654
  229. package/lib/errors/I18nError.js +0 -328
  230. package/lib/errors/ValidationError.js +0 -191
  231. package/lib/exporters/MarkdownExporter.js +0 -420
  232. package/lib/exporters/MongoDBExporter.js +0 -162
  233. package/lib/exporters/MySQLExporter.js +0 -212
  234. package/lib/exporters/PostgreSQLExporter.js +0 -289
  235. package/lib/exporters/index.js +0 -24
  236. package/lib/locales/index.js +0 -8
  237. package/lib/utils/LRUCache.js +0 -174
  238. package/lib/utils/SchemaHelper.js +0 -240
  239. package/lib/utils/SchemaUtils.js +0 -445
  240. package/lib/utils/TypeConverter.js +0 -245
  241. package/lib/utils/index.js +0 -13
  242. package/lib/validators/CustomKeywords.js +0 -616
  243. package/lib/validators/index.js +0 -11
@@ -1,490 +1,524 @@
1
- # Schema 工具函数文档
2
-
3
- > **更新时间**: 2025-12-25
4
-
5
- ---
6
-
7
- ## 📑 目录
8
-
9
- - [Schema 复用](#schema-复用)
10
- - [Schema 合并](#schema-合并)
11
- - [Schema 筛选](#schema-筛选)
12
- - [Schema 导出](#schema-导出)
13
- - [性能监控](#性能监控)
14
- - [完整示例](#完整示例)
15
-
16
- ---
17
-
18
- ## Schema 复用
19
-
20
- ### 直接复用(最简单)✅
21
-
22
- ```javascript
23
- const { dsl } = require('schema-dsl');
24
-
25
- // 定义可复用字段(就是普通对象)
26
- const commonFields = {
27
- email: 'email!'.label('邮箱地址'),
28
- phone: 'string:11!'.phone('cn').label('手机号'),
29
- username: 'string:3-32!'.username().label('用户名')
30
- };
31
-
32
- // 直接使用
33
- const registerSchema = dsl({
34
- ...commonFields, // ✅ 直接展开
35
- password: 'string:8-64!'.password('strong')
36
- });
37
-
38
- const profileSchema = dsl({
39
- ...commonFields, // ✅ 重复使用
40
- bio: 'string:500',
41
- avatar: 'url'
42
- });
43
- ```
44
-
45
- **优点**: 最简单,直接使用 JavaScript 对象展开
46
-
47
- ---
48
-
49
- ### 函数复用(需要参数时)
50
-
51
- ```javascript
52
- // 定义可复用字段函数
53
- const createEmailField = (label = '邮箱地址') =>
54
- 'email!'.label(label);
55
-
56
- const createRangeField = (min, max) =>
57
- `number:${min}-${max}`.label('数值范围');
58
-
59
- // 使用
60
- const schema = dsl({
61
- email: createEmailField('联系邮箱'),
62
- workEmail: createEmailField('工作邮箱'),
63
- age: createRangeField(18, 120),
64
- score: createRangeField(0, 100)
65
- });
66
- ```
67
-
68
- **优点**: 支持参数化,灵活性强
69
-
70
- ---
71
-
72
- ### 字段库复用(大型项目)
73
-
74
- ```javascript
75
- // fields/common.js - 定义字段库
76
- module.exports = {
77
- email: () => 'email!'.label('邮箱地址'),
78
- phone: (country = 'cn') => `string:11!`.phone(country).label('手机号'),
79
- username: (range = '3-32') => `string:${range}!`.username(range).label('用户名'),
80
- password: (strength = 'medium') => 'string:8-64!'.password(strength).label('密码'),
81
-
82
- // 组合字段
83
- userAuth: () => ({
84
- username: 'string:3-32!'.username().label('用户名'),
85
- password: 'string:8-64!'.password('strong').label('密码')
86
- }),
87
-
88
- userProfile: () => ({
89
- nickname: 'string:2-20!'.label('昵称'),
90
- bio: 'string:500',
91
- avatar: 'url'
92
- })
93
- };
94
-
95
- // 使用
96
- const fields = require('./fields/common');
97
-
98
- const loginSchema = dsl({
99
- email: fields.email(),
100
- password: fields.password('strong')
101
- });
102
-
103
- const registerSchema = dsl({
104
- ...fields.userAuth(), // ✅ 展开组合字段
105
- email: fields.email(),
106
- phone: fields.phone('cn')
107
- });
108
- ```
109
-
110
- **优点**: 统一管理,易于维护
111
-
112
- ---
113
-
114
- ## Schema 合并
115
-
116
- ### merge() - 合并多个Schema
117
-
118
- ```javascript
119
- const { SchemaUtils, dsl } = require('schema-dsl');
120
-
121
- // 基础Schema
122
- const baseUser = dsl({
123
- name: 'string:1-50!',
124
- email: 'email!'
125
- });
126
-
127
- // 扩展Schema
128
- const withAge = dsl({
129
- age: 'number:18-120',
130
- gender: 'male|female|other'
131
- });
132
-
133
- // 扩展
134
- const fullUser = SchemaUtils.extend(baseUser, {
135
- age: 'number:18-120',
136
- bio: 'string:500',
137
- avatar: 'url'
138
- });
139
- ```
140
-
141
- **说明**: 扩展字段,合并 properties 和 required 数组
142
-
143
- ---
144
-
145
- ### extend() - 扩展Schema(继承)
146
-
147
- ```javascript
148
- const baseUser = dsl({
149
- name: 'string!',
150
- email: 'email!'
151
- });
152
-
153
- // 扩展基础Schema
154
- const admin = SchemaUtils.extend(baseUser, {
155
- role: 'admin|superadmin',
156
- permissions: 'array<string>'
157
- });
158
-
159
- // admin包含所有baseUser字段 + role + permissions
160
- ```
161
-
162
- **说明**: 类似继承,保留基础Schema的所有字段
163
-
164
- ---
165
-
166
- ## Schema 筛选
167
-
168
- ### pick() - 选择字段
169
-
170
- ```javascript
171
- const fullUser = dsl({
172
- name: 'string!',
173
- email: 'email!',
174
- password: 'string:8-64!',
175
- phone: 'string:11!',
176
- age: 'number:18-120'
177
- });
178
-
179
- // 只选择特定字段
180
- const publicUser = SchemaUtils.pick(fullUser, ['name', 'email']);
181
-
182
- // publicUser 只包含 name 和 email
183
- ```
184
-
185
- **用途**: 从完整Schema中提取部分字段(如公开信息)
186
-
187
- ---
188
-
189
- ### omit() - 排除字段
190
-
191
- ```javascript
192
- const fullUser = dsl({
193
- name: 'string!',
194
- email: 'email!',
195
- password: 'string:8-64!',
196
- phone: 'string:11!'
197
- });
198
-
199
- // 排除敏感字段
200
- const safeUser = SchemaUtils.omit(fullUser, ['password']);
201
-
202
- // safeUser 包含除 password 外的所有字段
203
- ```
204
-
205
- **用途**: 移除敏感字段(如密码)
206
-
207
- ---
208
-
209
- ## Schema 导出
210
-
211
- ### toMarkdown() - 导出为Markdown文档
212
-
213
- ```javascript
214
- const schema = dsl({
215
- username: 'string:3-32!'.label('用户名'),
216
- email: 'email!'.label('邮箱地址'),
217
- age: 'number:18-120'
218
- });
219
-
220
- const markdown = SchemaUtils.toMarkdown(schema, {
221
- title: '用户注册Schema',
222
- showRequired: true,
223
- showType: true,
224
- showConstraints: true
225
- });
226
-
227
- console.log(markdown);
228
- ```
229
-
230
- **输出**:
231
- ```markdown
232
- # 用户注册Schema
233
-
234
- | 字段 | 类型 | 必填 | 约束 | 说明 |
235
- |------|------|------|------|------|
236
- | username | string | ✅ | 3-32字符 | 用户名 |
237
- | email | email | ✅ | - | 邮箱地址 |
238
- | age | number | ❌ | 18-120 | - |
239
- ```
240
-
241
- **用途**: 生成API文档
242
-
243
- ---
244
-
245
- ### toHTML() - 导出为HTML表格
246
-
247
- ```javascript
248
- const html = SchemaUtils.toHTML(schema, {
249
- title: '用户注册Schema',
250
- theme: 'bootstrap' // 或 'default'
251
- });
252
-
253
- // 生成HTML表格,可以嵌入文档
254
- ```
255
-
256
- **用途**: 集成到Web文档
257
-
258
- ---
259
-
260
- ## 性能监控
261
-
262
- ### validateBatch() - 批量验证
263
-
264
- ```javascript
265
- const { Validator } = require('schema-dsl');
266
-
267
- const schema = dsl({
268
- email: 'email!',
269
- age: 'number:18-120'
270
- });
271
-
272
- const validator = new Validator();
273
-
274
- const items = [
275
- { email: 'user1@example.com', age: 25 },
276
- { email: 'invalid', age: 15 },
277
- { email: 'user2@example.com', age: 30 }
278
- ];
279
-
280
- const results = validator.validateBatch(schema, items);
281
-
282
- console.log(results);
283
- // {
284
- // results: [
285
- // { valid: true, ... },
286
- // { valid: false, errors: [...] },
287
- // { valid: true, ... }
288
- // ],
289
- // stats: {
290
- // total: 3,
291
- // valid: 2,
292
- // invalid: 1,
293
- // duration: '5.2ms'
294
- // }
295
- // }
296
- ```
297
-
298
- **用途**: 批量验证数据,获取性能统计
299
-
300
- ---
301
-
302
- ### 性能监控(自动)
303
-
304
- ```javascript
305
- const validator = new Validator({ performance: true });
306
-
307
- const result = validator.validate(schema, data);
308
-
309
- console.log(result.performance);
310
- // {
311
- // duration: '2.1ms',
312
- // compileDuration: '1.5ms',
313
- // validateDuration: '0.6ms'
314
- // }
315
- ```
316
-
317
- **用途**: 监控验证性能
318
-
319
- ---
320
-
321
- ## 其他工具
322
-
323
- ### clone() - 深度克隆Schema
324
-
325
- ```javascript
326
- const original = dsl({
327
- user: {
328
- name: 'string!',
329
- profile: {
330
- bio: 'string:500'
331
- }
332
- }
333
- });
334
-
335
- const cloned = SchemaUtils.clone(original);
336
-
337
- // cloned 是完全独立的副本
338
- cloned.properties.user.properties.name.maxLength = 100;
339
- // original 不会被修改
340
- ```
341
-
342
- ---
343
-
344
- ### validateNestingDepth() - 检查嵌套深度
345
-
346
- ```javascript
347
- const schema = dsl({
348
- level1: {
349
- level2: {
350
- level3: {
351
- level4: 'string'
352
- }
353
- }
354
- }
355
- });
356
-
357
- const depth = schema.validateNestingDepth(10);
358
- // 返回: 4
359
-
360
- if (depth > 5) {
361
- console.warn('嵌套层级过深,建议扁平化');
362
- }
363
- ```
364
-
365
- **用途**: 防止过深嵌套
366
-
367
- ---
368
-
369
- ## 完整示例
370
-
371
- ### 企业级字段库
372
-
373
- ```javascript
374
- // libs/fields/index.js
375
- module.exports = {
376
- // 基础字段
377
- id: () => 'string!'.pattern(/^[a-zA-Z0-9_-]+$/).label('ID'),
378
- email: () => 'email!'.label('邮箱地址'),
379
- phone: (country = 'cn') => 'string:11!'.phone(country).label('手机号'),
380
-
381
- // 认证字段
382
- auth: {
383
- username: () => 'string:3-32!'.username().label('用户名'),
384
- password: (strength = 'strong') =>
385
- 'string:8-64!'.password(strength).label('密码')
386
- },
387
-
388
- // 个人信息
389
- profile: {
390
- nickname: () => 'string:2-20!'.label('昵称'),
391
- realName: () => 'string:2-50'.label('真实姓名'),
392
- bio: () => 'string:500',
393
- avatar: () => 'url'.label('头像'),
394
- birthday: () => 'date'
395
- },
396
-
397
- // 地址信息
398
- address: () => ({
399
- country: 'string:2-50!',
400
- province: 'string:2-50!',
401
- city: 'string:2-50!',
402
- detail: 'string:10-200!'
403
- }),
404
-
405
- // 时间戳
406
- timestamps: () => ({
407
- created_at: 'datetime!',
408
- updated_at: 'datetime!'
409
- })
410
- };
411
-
412
- // 使用
413
- const fields = require('./libs/fields');
414
-
415
- // 用户注册
416
- const registerSchema = dsl({
417
- ...fields.auth,
418
- email: fields.email(),
419
- phone: fields.phone('cn'),
420
- agree: 'boolean!'
421
- });
422
-
423
- // 用户资料
424
- const profileSchema = dsl({
425
- ...fields.profile,
426
- ...fields.timestamps()
427
- });
428
-
429
- // 完整用户
430
- const userSchema = SchemaUtils.extend(
431
- SchemaUtils.extend(registerSchema, profileSchema),
432
- fields.address()
433
- );
434
- ```
435
-
436
- ---
437
-
438
- ## 最佳实践
439
-
440
- ### 1. 小项目:直接复用
441
-
442
- ```javascript
443
- const commonFields = {
444
- email: 'email!'.label('邮箱'),
445
- phone: 'string:11!'.phone('cn')
446
- };
447
-
448
- const schema1 = dsl({ ...commonFields, ... });
449
- const schema2 = dsl({ ...commonFields, ... });
450
- ```
451
-
452
- ### 2. 中型项目:函数复用
453
-
454
- ```javascript
455
- const createUserFields = (options = {}) => ({
456
- email: 'email!'.label(options.emailLabel || '邮箱'),
457
- phone: 'string:11!'.phone(options.country || 'cn')
458
- });
459
-
460
- const schema = dsl({
461
- ...createUserFields({ emailLabel: '联系邮箱' }),
462
- ...otherFields
463
- });
464
- ```
465
-
466
- ### 3. 大型项目:字段库
467
-
468
- ```javascript
469
- // 统一管理在 fields/ 目录
470
- const fields = require('./fields');
471
-
472
- const schema = dsl({
473
- ...fields.auth,
474
- ...fields.profile
475
- });
476
- ```
477
-
478
- ---
479
-
480
- ## 相关文档
481
-
482
- - [DSL 语法](./dsl-syntax.md)
483
- - [String 扩展](./string-extensions.md)
484
- - [API 参考](./api-reference.md)
485
-
486
- ---
487
-
488
- **最后更新**: 2025-12-25
489
-
490
-
1
+ # Schema 工具函数文档
2
+
3
+ > **更新时间**: 2025-12-25
4
+
5
+ ---
6
+
7
+ ## 📑 目录
8
+
9
+ - [Schema 复用](#schema-复用)
10
+ - [Schema 合并](#schema-合并)
11
+ - [Schema 筛选](#schema-筛选)
12
+ - [Schema 导出](#schema-导出)
13
+ - [性能监控](#性能监控)
14
+ - [完整示例](#完整示例)
15
+
16
+ ---
17
+
18
+ ## Schema 复用
19
+
20
+ ### 直接复用(最简单)✅
21
+
22
+ ```javascript
23
+ const { dsl } = require('schema-dsl');
24
+
25
+ // 定义可复用字段(就是普通对象)
26
+ const commonFields = {
27
+ email: 'email!'.label('邮箱地址'),
28
+ phone: 'string:11!'.phone('cn').label('手机号'),
29
+ username: 'string:3-32!'.username().label('用户名')
30
+ };
31
+
32
+ // 直接使用
33
+ const registerSchema = dsl({
34
+ ...commonFields, // ✅ 直接展开
35
+ password: 'string:8-64!'.password('strong')
36
+ });
37
+
38
+ const profileSchema = dsl({
39
+ ...commonFields, // ✅ 重复使用
40
+ bio: 'string:500',
41
+ avatar: 'url'
42
+ });
43
+ ```
44
+
45
+ **优点**: 最简单,直接使用 JavaScript 对象展开
46
+
47
+ ---
48
+
49
+ ### 函数复用(需要参数时)
50
+
51
+ ```javascript
52
+ // 定义可复用字段函数
53
+ const createEmailField = (label = '邮箱地址') =>
54
+ 'email!'.label(label);
55
+
56
+ const createRangeField = (min, max) =>
57
+ `number:${min}-${max}`.label('数值范围');
58
+
59
+ // 使用
60
+ const schema = dsl({
61
+ email: createEmailField('联系邮箱'),
62
+ workEmail: createEmailField('工作邮箱'),
63
+ age: createRangeField(18, 120),
64
+ score: createRangeField(0, 100)
65
+ });
66
+ ```
67
+
68
+ **优点**: 支持参数化,灵活性强
69
+
70
+ ---
71
+
72
+ ### 字段库复用(大型项目)
73
+
74
+ ```javascript
75
+ // fields/common.js - 定义字段库
76
+ module.exports = {
77
+ email: () => 'email!'.label('邮箱地址'),
78
+ phone: (country = 'cn') => `string:11!`.phone(country).label('手机号'),
79
+ username: (range = '3-32') => `string:${range}!`.username(range).label('用户名'),
80
+ password: (strength = 'medium') => 'string:8-64!'.password(strength).label('密码'),
81
+
82
+ // 组合字段
83
+ userAuth: () => ({
84
+ username: 'string:3-32!'.username().label('用户名'),
85
+ password: 'string:8-64!'.password('strong').label('密码')
86
+ }),
87
+
88
+ userProfile: () => ({
89
+ nickname: 'string:2-20!'.label('昵称'),
90
+ bio: 'string:500',
91
+ avatar: 'url'
92
+ })
93
+ };
94
+
95
+ // 使用
96
+ const fields = require('./fields/common');
97
+
98
+ const loginSchema = dsl({
99
+ email: fields.email(),
100
+ password: fields.password('strong')
101
+ });
102
+
103
+ const registerSchema = dsl({
104
+ ...fields.userAuth(), // ✅ 展开组合字段
105
+ email: fields.email(),
106
+ phone: fields.phone('cn')
107
+ });
108
+ ```
109
+
110
+ **优点**: 统一管理,易于维护
111
+
112
+ ---
113
+
114
+ ## Schema 合并
115
+
116
+ ### createLibrary() - 创建片段库
117
+
118
+ ```javascript
119
+ const { SchemaUtils, dsl } = require('schema-dsl');
120
+
121
+ const fields = SchemaUtils.createLibrary({
122
+ email: () => 'email!'.label('邮箱地址'),
123
+ phone: () => dsl('string!').phone('cn').label('手机号'),
124
+ profile: () => ({
125
+ bio: 'string:500',
126
+ avatar: 'url'
127
+ })
128
+ });
129
+
130
+ const registerSchema = dsl({
131
+ email: fields.email(),
132
+ phone: fields.phone(),
133
+ password: dsl('string!').password('strong')
134
+ });
135
+
136
+ const profileSchema = dsl({
137
+ ...fields.profile(),
138
+ email: fields.email()
139
+ });
140
+ ```
141
+
142
+ **说明**: `createLibrary()` 只是返回片段工厂集合,适合在大型项目中集中管理字段和组合片段。
143
+
144
+ ---
145
+
146
+ ### extend() - 扩展Schema(继承)
147
+
148
+ ```javascript
149
+ const baseUser = dsl({
150
+ name: 'string!',
151
+ email: 'email!'
152
+ });
153
+
154
+ // 扩展基础Schema
155
+ const admin = SchemaUtils.extend(baseUser, {
156
+ role: 'admin|superadmin',
157
+ permissions: 'array<string>'
158
+ });
159
+
160
+ // admin包含所有baseUser字段 + role + permissions
161
+ ```
162
+
163
+ **说明**: 类似继承,保留基础Schema的所有字段
164
+
165
+ ---
166
+
167
+ ## Schema 筛选
168
+
169
+ ### pick() - 选择字段
170
+
171
+ ```javascript
172
+ const fullUser = dsl({
173
+ name: 'string!',
174
+ email: 'email!',
175
+ password: 'string:8-64!',
176
+ phone: 'string:11!',
177
+ age: 'number:18-120'
178
+ });
179
+
180
+ // 只选择特定字段
181
+ const publicUser = SchemaUtils.pick(fullUser, ['name', 'email']);
182
+
183
+ // publicUser 只包含 name 和 email
184
+ ```
185
+
186
+ **用途**: 从完整Schema中提取部分字段(如公开信息)
187
+
188
+ ---
189
+
190
+ ### omit() - 排除字段
191
+
192
+ ```javascript
193
+ const fullUser = dsl({
194
+ name: 'string!',
195
+ email: 'email!',
196
+ password: 'string:8-64!',
197
+ phone: 'string:11!'
198
+ });
199
+
200
+ // 排除敏感字段
201
+ const safeUser = SchemaUtils.omit(fullUser, ['password']);
202
+
203
+ // safeUser 包含除 password 外的所有字段
204
+ ```
205
+
206
+ **用途**: 移除敏感字段(如密码)
207
+
208
+ ---
209
+
210
+ ### partial() - 将字段改为可选
211
+
212
+ ```javascript
213
+ const updateSchema = SchemaUtils.partial(dsl({
214
+ name: 'string!',
215
+ email: 'email!',
216
+ age: 'number:18-120'
217
+ }));
218
+
219
+ // 结果中 required 会被移除,适合 PATCH / 局部更新场景
220
+ ```
221
+
222
+ 也可以只对部分字段做可选化:
223
+
224
+ ```javascript
225
+ const schema = dsl({
226
+ name: 'string!',
227
+ email: 'email!',
228
+ age: 'number:18-120'
229
+ });
230
+
231
+ const partialContact = SchemaUtils.partial(schema, ['name', 'email']);
232
+ ```
233
+
234
+ ---
235
+
236
+ ## Schema 导出
237
+
238
+ ### toMarkdown() - 导出为Markdown文档
239
+
240
+ ```javascript
241
+ const schema = dsl({
242
+ username: 'string:3-32!'.label('用户名'),
243
+ email: 'email!'.label('邮箱地址'),
244
+ age: 'number:18-120'
245
+ });
246
+
247
+ const markdown = SchemaUtils.toMarkdown(schema, {
248
+ title: '用户注册Schema'
249
+ });
250
+
251
+ console.log(markdown);
252
+ ```
253
+
254
+ **输出**:
255
+ ```markdown
256
+ # 用户注册Schema
257
+
258
+ | 字段 | 类型 | 必填 | 约束 | 说明 |
259
+ |------|------|------|------|------|
260
+ | username | string | ✅ | 3-32字符 | 用户名 |
261
+ | email | email | ✅ | - | 邮箱地址 |
262
+ | age | number | ❌ | 18-120 | - |
263
+ ```
264
+
265
+ **用途**: 生成API文档
266
+
267
+ ---
268
+
269
+ ### toHTML() - 导出为HTML表格
270
+
271
+ ```javascript
272
+ const html = SchemaUtils.toHTML(schema, {
273
+ title: '用户注册Schema'
274
+ });
275
+
276
+ // 生成HTML表格,可以嵌入文档
277
+ ```
278
+
279
+ **用途**: 集成到Web文档
280
+
281
+ ---
282
+
283
+ ## 性能监控
284
+
285
+ ### validateBatch() - 批量验证统计
286
+
287
+ ```javascript
288
+ const { SchemaUtils, Validator, dsl } = require('schema-dsl');
289
+
290
+ const schema = dsl({
291
+ email: 'email!',
292
+ age: 'number:18-120'
293
+ });
294
+
295
+ const validator = new Validator();
296
+
297
+ const items = [
298
+ { email: 'user1@example.com', age: 25 },
299
+ { email: 'invalid', age: 15 },
300
+ { email: 'user2@example.com', age: 30 }
301
+ ];
302
+
303
+ const batch = SchemaUtils.validateBatch(schema, items, validator.getAjv());
304
+
305
+ console.log(batch);
306
+ // {
307
+ // results: [
308
+ // { index: 0, valid: true, errors: null, data: {...} },
309
+ // { index: 1, valid: false, errors: [...], data: null },
310
+ // { index: 2, valid: true, errors: null, data: {...} }
311
+ // ],
312
+ // summary: {
313
+ // total: 3,
314
+ // valid: 2,
315
+ // invalid: 1,
316
+ // duration: 5,
317
+ // averageTime: 1.67
318
+ // }
319
+ // }
320
+ ```
321
+
322
+ **说明**:
323
+ - 如果你只需要“每条是否通过”的结果,可直接使用 `validator.validateBatch(schema, items)`
324
+ - 如果你还需要汇总统计信息,再使用 `SchemaUtils.validateBatch(schema, items, validator.getAjv())`
325
+
326
+ ---
327
+
328
+ ### withPerformance() - 给 Validator 添加性能包装
329
+
330
+ ```javascript
331
+ const validator = SchemaUtils.withPerformance(new Validator());
332
+
333
+ const result = validator.validate(schema, data);
334
+
335
+ console.log(result.performance);
336
+ // {
337
+ // duration: 2,
338
+ // timestamp: '2026-05-06T12:34:56.789Z'
339
+ // }
340
+ ```
341
+
342
+ **用途**: 在不改业务调用方式的前提下,为验证结果附加耗时信息
343
+
344
+ ---
345
+
346
+ ## 其他工具
347
+
348
+ ### clone() - 深度克隆Schema
349
+
350
+ ```javascript
351
+ const original = dsl({
352
+ user: {
353
+ name: 'string!',
354
+ profile: {
355
+ bio: 'string:500'
356
+ }
357
+ }
358
+ });
359
+
360
+ const cloned = SchemaUtils.clone(original);
361
+
362
+ // cloned 是完全独立的副本
363
+ cloned.properties.user.properties.name.maxLength = 100;
364
+ // original 不会被修改
365
+ ```
366
+
367
+ ---
368
+
369
+ ### validateNestingDepth() - 检查嵌套深度
370
+
371
+ ```javascript
372
+ const { dsl, DslBuilder } = require('schema-dsl');
373
+
374
+ const schema = dsl({
375
+ level1: {
376
+ level2: {
377
+ level3: {
378
+ level4: 'string'
379
+ }
380
+ }
381
+ }
382
+ });
383
+
384
+ const result = DslBuilder.validateNestingDepth(schema, 10);
385
+ // 返回: { valid: true, depth: 4, path: 'level1.level2.level3', message: '...' }
386
+
387
+ if (result.depth > 5) {
388
+ console.warn('嵌套层级过深,建议扁平化');
389
+ }
390
+ ```
391
+
392
+ **说明**: 这个能力属于 `DslBuilder` 静态方法,不是 `SchemaUtils` 的成员;这里一并列出是因为它常与 Schema 工具链一起使用。
393
+
394
+ ---
395
+
396
+ ## 完整示例
397
+
398
+ ### 企业级字段库
399
+
400
+ ```javascript
401
+ // libs/fields/index.js
402
+ module.exports = {
403
+ // 基础字段
404
+ id: () => 'string!'.pattern(/^[a-zA-Z0-9_-]+$/).label('ID'),
405
+ email: () => 'email!'.label('邮箱地址'),
406
+ phone: (country = 'cn') => 'string:11!'.phone(country).label('手机号'),
407
+
408
+ // 认证字段
409
+ auth: {
410
+ username: () => 'string:3-32!'.username().label('用户名'),
411
+ password: (strength = 'strong') =>
412
+ 'string:8-64!'.password(strength).label('密码')
413
+ },
414
+
415
+ // 个人信息
416
+ profile: {
417
+ nickname: () => 'string:2-20!'.label('昵称'),
418
+ realName: () => 'string:2-50'.label('真实姓名'),
419
+ bio: () => 'string:500',
420
+ avatar: () => 'url'.label('头像'),
421
+ birthday: () => 'date'
422
+ },
423
+
424
+ // 地址信息
425
+ address: () => ({
426
+ country: 'string:2-50!',
427
+ province: 'string:2-50!',
428
+ city: 'string:2-50!',
429
+ detail: 'string:10-200!'
430
+ }),
431
+
432
+ // 时间戳
433
+ timestamps: () => ({
434
+ created_at: 'datetime!',
435
+ updated_at: 'datetime!'
436
+ })
437
+ };
438
+
439
+ // 使用
440
+ const fields = require('./libs/fields');
441
+
442
+ // 用户注册
443
+ const registerSchema = dsl({
444
+ ...fields.auth,
445
+ email: fields.email(),
446
+ phone: fields.phone('cn'),
447
+ agree: 'boolean!'
448
+ });
449
+
450
+ // 用户资料
451
+ const profileSchema = dsl({
452
+ ...fields.profile,
453
+ ...fields.timestamps()
454
+ });
455
+
456
+ // 完整用户
457
+ const userSchema = SchemaUtils.extend(
458
+ SchemaUtils.extend(registerSchema, profileSchema),
459
+ fields.address()
460
+ );
461
+ ```
462
+
463
+ ---
464
+
465
+ ## 最佳实践
466
+
467
+ ### 1. 小项目:直接复用
468
+
469
+ ```javascript
470
+ const commonFields = {
471
+ email: 'email!'.label('邮箱'),
472
+ phone: 'string:11!'.phone('cn')
473
+ };
474
+
475
+ const schema1 = dsl({ ...commonFields, ... });
476
+ const schema2 = dsl({ ...commonFields, ... });
477
+ ```
478
+
479
+ ### 2. 中型项目:函数复用
480
+
481
+ ```javascript
482
+ const createUserFields = (options = {}) => ({
483
+ email: 'email!'.label(options.emailLabel || '邮箱'),
484
+ phone: 'string:11!'.phone(options.country || 'cn')
485
+ });
486
+
487
+ const schema = dsl({
488
+ ...createUserFields({ emailLabel: '联系邮箱' }),
489
+ ...otherFields
490
+ });
491
+ ```
492
+
493
+ ### 3. 大型项目:字段库
494
+
495
+ ```javascript
496
+ // 统一管理在 fields/ 目录
497
+ const fields = require('./fields');
498
+
499
+ const schema = dsl({
500
+ ...fields.auth,
501
+ ...fields.profile
502
+ });
503
+ ```
504
+
505
+ ---
506
+
507
+ ## 相关文档
508
+
509
+ - [DSL 语法](./dsl-syntax.md)
510
+ - [String 扩展](./string-extensions.md)
511
+ - [API 参考](./api-reference.md)
512
+
513
+ ---
514
+
515
+ ## 对应示例文件
516
+
517
+ **示例入口**: [schema-utils.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/schema-utils.ts)
518
+ **说明**: 覆盖 `reusable()`、`createLibrary()`、`extend()`、`validateBatch()`、`withPerformance()` 和 `clone()` 的最小工作流。
519
+
520
+ ---
521
+
522
+ **最后更新**: 2026-05-08
523
+
524
+