schema-dsl 1.2.4 → 2.0.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.
Files changed (242) hide show
  1. package/CHANGELOG.md +87 -210
  2. package/README.md +391 -2249
  3. package/dist/DslBuilder-DQDN0ZxZ.d.cts +341 -0
  4. package/dist/DslBuilder-DkLaOo9Q.d.ts +341 -0
  5. package/dist/Validator-C7GsVQOH.d.cts +192 -0
  6. package/dist/Validator-hFWKGxir.d.ts +192 -0
  7. package/dist/index.cjs +6594 -0
  8. package/dist/index.d.cts +1145 -0
  9. package/dist/index.d.ts +1145 -0
  10. package/dist/index.js +6528 -0
  11. package/dist/plugin-CIKtTMtS.d.cts +246 -0
  12. package/dist/plugin-CIKtTMtS.d.ts +246 -0
  13. package/dist/plugins/custom-format.cjs +3802 -0
  14. package/dist/plugins/custom-format.d.cts +12 -0
  15. package/dist/plugins/custom-format.d.ts +12 -0
  16. package/dist/plugins/custom-format.js +3772 -0
  17. package/dist/plugins/custom-type-example.cjs +3795 -0
  18. package/dist/plugins/custom-type-example.d.cts +8 -0
  19. package/dist/plugins/custom-type-example.d.ts +8 -0
  20. package/dist/plugins/custom-type-example.js +3765 -0
  21. package/dist/plugins/custom-validator.cjs +146 -0
  22. package/dist/plugins/custom-validator.d.cts +10 -0
  23. package/dist/plugins/custom-validator.d.ts +10 -0
  24. package/dist/plugins/custom-validator.js +121 -0
  25. package/docs/FEATURE-INDEX.md +102 -68
  26. package/docs/add-custom-locale.md +48 -35
  27. package/docs/add-keyword.md +24 -0
  28. package/docs/api-reference.md +396 -154
  29. package/docs/api.md +13 -0
  30. package/docs/best-practices-project-structure.md +19 -10
  31. package/docs/best-practices.md +93 -53
  32. package/docs/cache-manager.md +23 -15
  33. package/docs/compile.md +45 -0
  34. package/docs/conditional-api.md +40 -11
  35. package/docs/custom-extensions-guide.md +80 -152
  36. package/docs/design-philosophy.md +76 -71
  37. package/docs/doc-index.md +324 -0
  38. package/docs/dsl-syntax.md +69 -19
  39. package/docs/dynamic-locale.md +24 -14
  40. package/docs/enum.md +12 -5
  41. package/docs/error-handling.md +53 -44
  42. package/docs/export-guide.md +47 -8
  43. package/docs/export-limitations.md +27 -11
  44. package/docs/faq.md +86 -67
  45. package/docs/frontend-i18n-guide.md +26 -12
  46. package/docs/i18n-user-guide.md +60 -47
  47. package/docs/i18n.md +51 -32
  48. package/docs/index.md +48 -0
  49. package/docs/json-schema-basics.md +40 -0
  50. package/docs/label-vs-description.md +12 -3
  51. package/docs/markdown-exporter.md +15 -6
  52. package/docs/mongodb-exporter.md +11 -4
  53. package/docs/multi-language.md +26 -0
  54. package/docs/multi-type-support.md +26 -33
  55. package/docs/mysql-exporter.md +9 -2
  56. package/docs/number-operators.md +12 -5
  57. package/docs/optional-marker-guide.md +28 -23
  58. package/docs/performance-guide.md +49 -0
  59. package/docs/plugin-system.md +205 -366
  60. package/docs/plugin-type-registration.md +34 -0
  61. package/docs/postgresql-exporter.md +9 -2
  62. package/docs/public/favicon.svg +5 -0
  63. package/docs/quick-start.md +37 -363
  64. package/docs/runtime-locale-support.md +20 -9
  65. package/docs/schema-helper.md +10 -5
  66. package/docs/schema-utils-advanced-issues.md +23 -0
  67. package/docs/schema-utils-best-practices.md +20 -0
  68. package/docs/schema-utils-chaining.md +7 -0
  69. package/docs/schema-utils.md +76 -42
  70. package/docs/security-checklist.md +20 -0
  71. package/docs/string-extensions.md +17 -9
  72. package/docs/troubleshooting.md +36 -21
  73. package/docs/type-converter.md +41 -50
  74. package/docs/type-reference.md +38 -15
  75. package/docs/typescript-guide.md +53 -42
  76. package/docs/union-type-guide.md +11 -1
  77. package/docs/union-types.md +10 -3
  78. package/docs/validate-async.md +36 -25
  79. package/docs/validate-batch.md +49 -0
  80. package/docs/validate-dsl-object-support.md +33 -28
  81. package/docs/validate.md +36 -16
  82. package/docs/validation-guide.md +25 -7
  83. package/docs/validator.md +39 -0
  84. package/package.json +85 -27
  85. package/plugins/custom-format.cjs +8 -0
  86. package/plugins/custom-type-example.cjs +8 -0
  87. package/plugins/custom-validator.cjs +8 -0
  88. package/src/adapters/DslAdapter.ts +111 -0
  89. package/src/adapters/index.ts +1 -0
  90. package/src/config/constants.ts +83 -0
  91. package/src/config/index.ts +2 -0
  92. package/src/config/patterns.ts +77 -0
  93. package/src/core/CacheManager.ts +159 -0
  94. package/src/core/ConditionalBuilder.ts +382 -0
  95. package/src/core/ConditionalRuntime.ts +28 -0
  96. package/src/core/ConditionalValidator.ts +255 -0
  97. package/src/core/DslBuilder.ts +677 -0
  98. package/src/core/ErrorCodes.ts +38 -0
  99. package/src/core/ErrorFormatter.ts +271 -0
  100. package/src/core/JSONSchemaCore.ts +65 -0
  101. package/src/core/Locale.ts +187 -0
  102. package/src/core/MessageTemplate.ts +42 -0
  103. package/src/core/ObjectDslBuilder.ts +64 -0
  104. package/src/core/PluginManager.ts +326 -0
  105. package/src/core/StringExtensions.ts +140 -0
  106. package/src/core/TemplateEngine.ts +44 -0
  107. package/src/core/Validator.ts +448 -0
  108. package/src/errors/I18nError.ts +159 -0
  109. package/src/errors/ValidationError.ts +105 -0
  110. package/src/exporters/BaseExporter.ts +60 -0
  111. package/src/exporters/MarkdownExporter.ts +305 -0
  112. package/src/exporters/MongoDBExporter.ts +126 -0
  113. package/src/exporters/MySQLExporter.ts +155 -0
  114. package/src/exporters/PostgreSQLExporter.ts +222 -0
  115. package/src/exporters/index.ts +18 -0
  116. package/src/index.ts +633 -0
  117. package/{lib/locales/en-US.js → src/locales/en-US.ts} +21 -37
  118. package/{lib/locales/es-ES.js → src/locales/es-ES.ts} +63 -16
  119. package/{lib/locales/fr-FR.js → src/locales/fr-FR.ts} +74 -27
  120. package/src/locales/index.ts +103 -0
  121. package/{lib/locales/ja-JP.js → src/locales/ja-JP.ts} +59 -17
  122. package/src/locales/types.ts +156 -0
  123. package/{lib/locales/zh-CN.js → src/locales/zh-CN.ts} +21 -38
  124. package/src/parser/ConstraintParser.ts +101 -0
  125. package/src/parser/DslParser.ts +470 -0
  126. package/src/parser/SchemaCompiler.ts +66 -0
  127. package/src/parser/TypeRegistry.ts +250 -0
  128. package/src/parser/index.ts +6 -0
  129. package/src/plugins/custom-format.ts +126 -0
  130. package/src/plugins/custom-type-example.ts +108 -0
  131. package/src/plugins/custom-validator.ts +140 -0
  132. package/src/types/conditional.ts +28 -0
  133. package/src/types/config.ts +59 -0
  134. package/src/types/dsl.ts +131 -0
  135. package/src/types/error.ts +60 -0
  136. package/src/types/index.ts +17 -0
  137. package/src/types/infer.ts +128 -0
  138. package/src/types/plugin.ts +58 -0
  139. package/src/types/safe-regex.d.ts +9 -0
  140. package/src/types/schema.ts +66 -0
  141. package/src/types/validate.ts +71 -0
  142. package/src/utils/SchemaHelper.ts +196 -0
  143. package/src/utils/SchemaUtils.ts +346 -0
  144. package/src/utils/TypeConverter.ts +215 -0
  145. package/src/utils/index.ts +10 -0
  146. package/src/validators/CustomKeywords.ts +477 -0
  147. package/.eslintignore +0 -11
  148. package/.eslintrc.json +0 -27
  149. package/CONTRIBUTING.md +0 -368
  150. package/STATUS.md +0 -491
  151. package/changelogs/v1.0.0.md +0 -328
  152. package/changelogs/v1.0.9.md +0 -367
  153. package/changelogs/v1.1.0.md +0 -389
  154. package/changelogs/v1.1.1.md +0 -308
  155. package/changelogs/v1.1.2.md +0 -183
  156. package/changelogs/v1.1.3.md +0 -161
  157. package/changelogs/v1.1.4.md +0 -432
  158. package/changelogs/v1.1.5.md +0 -493
  159. package/changelogs/v1.1.6.md +0 -211
  160. package/changelogs/v1.1.8.md +0 -376
  161. package/changelogs/v1.2.3.md +0 -124
  162. package/docs/INDEX.md +0 -252
  163. package/docs/issues-resolved-summary.md +0 -196
  164. package/docs/performance-benchmark-report.md +0 -179
  165. package/docs/performance-quick-reference.md +0 -123
  166. package/docs/user-questions-answered.md +0 -353
  167. package/docs/validation-rules-v1.0.2.md +0 -1608
  168. package/examples/README.md +0 -81
  169. package/examples/array-dsl-example.js +0 -227
  170. package/examples/conditional-example.js +0 -288
  171. package/examples/conditional-non-object.js +0 -129
  172. package/examples/conditional-validate-example.js +0 -321
  173. package/examples/custom-extension.js +0 -85
  174. package/examples/dsl-match-example.js +0 -74
  175. package/examples/dsl-style.js +0 -118
  176. package/examples/dynamic-locale-configuration.js +0 -348
  177. package/examples/dynamic-locale-example.js +0 -287
  178. package/examples/enum.examples.js +0 -324
  179. package/examples/export-demo.js +0 -130
  180. package/examples/express-integration.js +0 -376
  181. package/examples/i18n-error-handling-complete.js +0 -381
  182. package/examples/i18n-error-handling-quickstart.md +0 -0
  183. package/examples/i18n-error.examples.js +0 -181
  184. package/examples/i18n-full-demo.js +0 -301
  185. package/examples/i18n-memory-safety.examples.js +0 -268
  186. package/examples/markdown-export.js +0 -71
  187. package/examples/middleware-usage.js +0 -93
  188. package/examples/new-features-comparison.js +0 -315
  189. package/examples/password-reset/README.md +0 -153
  190. package/examples/password-reset/schema.js +0 -26
  191. package/examples/password-reset/test.js +0 -101
  192. package/examples/plugin-system.examples.js +0 -205
  193. package/examples/schema-utils-chaining.examples.js +0 -250
  194. package/examples/simple-example.js +0 -122
  195. package/examples/slug.examples.js +0 -179
  196. package/examples/string-extensions.js +0 -297
  197. package/examples/union-type-example.js +0 -127
  198. package/examples/union-types-example.js +0 -77
  199. package/examples/user-registration/README.md +0 -156
  200. package/examples/user-registration/routes.js +0 -92
  201. package/examples/user-registration/schema.js +0 -150
  202. package/examples/user-registration/server.js +0 -74
  203. package/index.d.ts +0 -3540
  204. package/index.js +0 -457
  205. package/index.mjs +0 -60
  206. package/lib/adapters/DslAdapter.js +0 -871
  207. package/lib/adapters/index.js +0 -20
  208. package/lib/config/constants.js +0 -286
  209. package/lib/config/patterns/common.js +0 -47
  210. package/lib/config/patterns/creditCard.js +0 -9
  211. package/lib/config/patterns/idCard.js +0 -9
  212. package/lib/config/patterns/index.js +0 -9
  213. package/lib/config/patterns/licensePlate.js +0 -4
  214. package/lib/config/patterns/passport.js +0 -4
  215. package/lib/config/patterns/phone.js +0 -9
  216. package/lib/config/patterns/postalCode.js +0 -5
  217. package/lib/core/CacheManager.js +0 -376
  218. package/lib/core/ConditionalBuilder.js +0 -503
  219. package/lib/core/DslBuilder.js +0 -1400
  220. package/lib/core/ErrorCodes.js +0 -233
  221. package/lib/core/ErrorFormatter.js +0 -445
  222. package/lib/core/JSONSchemaCore.js +0 -347
  223. package/lib/core/Locale.js +0 -130
  224. package/lib/core/MessageTemplate.js +0 -98
  225. package/lib/core/PluginManager.js +0 -448
  226. package/lib/core/StringExtensions.js +0 -240
  227. package/lib/core/Validator.js +0 -654
  228. package/lib/errors/I18nError.js +0 -328
  229. package/lib/errors/ValidationError.js +0 -191
  230. package/lib/exporters/MarkdownExporter.js +0 -420
  231. package/lib/exporters/MongoDBExporter.js +0 -162
  232. package/lib/exporters/MySQLExporter.js +0 -212
  233. package/lib/exporters/PostgreSQLExporter.js +0 -289
  234. package/lib/exporters/index.js +0 -24
  235. package/lib/locales/index.js +0 -8
  236. package/lib/utils/LRUCache.js +0 -174
  237. package/lib/utils/SchemaHelper.js +0 -240
  238. package/lib/utils/SchemaUtils.js +0 -445
  239. package/lib/utils/TypeConverter.js +0 -245
  240. package/lib/utils/index.js +0 -13
  241. package/lib/validators/CustomKeywords.js +0 -616
  242. package/lib/validators/index.js +0 -11
package/docs/api.md ADDED
@@ -0,0 +1,13 @@
1
+ # API 参考入口
2
+
3
+ 完整 API 参考请见:[api-reference.md](./api-reference.md)。
4
+
5
+ 本文件用于兼容历史文档中的 `./api.md` 链接。
6
+
7
+ ---
8
+
9
+ ## 对应示例文件
10
+
11
+ **示例入口**: [api.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/api.ts)
12
+ **说明**: 以最小入口串起 `dsl()`、`validate()`、`Validator.validateAsync()` 和 `TypeConverter` 这些最常用公开 API。
13
+
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## 推荐的项目结构
4
4
 
5
- ```
5
+ ```text
6
6
  your-project/
7
7
  ├── schemas/ # ✅ 所有 schema 定义(项目启动时加载)
8
8
  │ ├── index.js # 统一导出
@@ -49,7 +49,7 @@ const userSchemas = {
49
49
  'string.email': '请输入有效的邮箱地址'
50
50
  }),
51
51
 
52
- password: dsl('password:strong!')
52
+ password: dsl('string!').password('strong')
53
53
  .label('密码')
54
54
  .messages({
55
55
  'string.password': '密码必须包含大小写字母、数字和特殊字符'
@@ -82,7 +82,7 @@ const userSchemas = {
82
82
  // 修改密码 schema
83
83
  changePassword: dsl({
84
84
  oldPassword: 'string!',
85
- newPassword: 'password:strong!'
85
+ newPassword: dsl('string!').password('strong')
86
86
  })
87
87
  };
88
88
 
@@ -236,7 +236,7 @@ app.use('/api/product', require('./routes/product'));
236
236
  const PORT = process.env.PORT || 3000;
237
237
  app.listen(PORT, () => {
238
238
  console.log(`✅ Server started on port ${PORT}`);
239
- console.log('✅ All schemas are pre-compiled and ready to use');
239
+ console.log('✅ All schemas are loaded and ready to validate');
240
240
  });
241
241
 
242
242
  module.exports = app;
@@ -255,7 +255,7 @@ router.post('/register', (req, res) => {
255
255
  { // ❌ 每次请求都转换
256
256
  username: 'string:3-32!',
257
257
  email: 'email!',
258
- password: 'password:strong!'
258
+ password: dsl('string!').password('strong')
259
259
  },
260
260
  req.body
261
261
  );
@@ -297,9 +297,9 @@ router.post('/register', (req, res) => {
297
297
  | **生产环境 API** | ✅ 项目启动时配置 | `const schemas = require('./schemas')` | 避免每次请求都转换 |
298
298
  | **高并发服务** | ✅ 项目启动时配置 | 同上 | 3-5% 的性能损失会被放大 |
299
299
  | **微服务** | ✅ 项目启动时配置 | 同上 | 保证响应时间稳定 |
300
- | **单次脚本** | ✅ 直接用 DSL 对象 | `validate({ email: 'email!' }, data)` | 只执行一次,性能影响可忽略 |
301
- | **原型开发** | ✅ 直接用 DSL 对象 | 同上 | 快速迭代,无需在意性能 |
302
- | **测试代码** | ✅ 直接用 DSL 对象 | 同上 | 简洁清晰,易于维护 |
300
+ | **单次脚本** | ✅ 直接用 DSL 对象(当前版便捷函数支持) | `validate({ email: 'email!' }, data)` | 只执行一次,性能影响可忽略 |
301
+ | **原型开发** | ✅ 直接用 DSL 对象(当前版便捷函数支持) | 同上 | 快速迭代,无需在意性能 |
302
+ | **测试代码** | ✅ 直接用 DSL 对象(当前版便捷函数支持) | 同上 | 简洁清晰,易于维护 |
303
303
 
304
304
  ---
305
305
 
@@ -365,9 +365,11 @@ export const userSchemas = {
365
365
  register: dsl({
366
366
  username: dsl('string:3-32!')
367
367
  .pattern(/^[a-zA-Z0-9_]+$/)
368
- .messages({ 'string.pattern': '只能包含字母、数字和下划线' }),
368
+ .error({ pattern: '只能包含字母、数字和下划线' }),
369
369
  email: 'email!',
370
- password: 'password:strong!',
370
+ password: dsl('string:8-64!')
371
+ .pattern(/^(?=.*[A-Za-z])(?=.*\d).{8,}$/)
372
+ .error({ pattern: '密码至少 8 位且必须包含字母和数字' }),
371
373
  age: 'number:18-120'
372
374
  }),
373
375
 
@@ -406,3 +408,10 @@ router.post('/register', (req, res) => {
406
408
  - 集中管理所有验证规则
407
409
  - 易于维护和修改
408
410
  - 类型安全(TypeScript)
411
+
412
+ ---
413
+
414
+ ## 对应示例文件
415
+
416
+ **示例入口**: [best-practices-project-structure.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/best-practices-project-structure.ts)
417
+ **说明**: 用一个最小的 `userSchemas` 对象模拟集中定义 / 路由复用结构,直接验证注册与登录两条路径。
@@ -1,7 +1,7 @@
1
1
  # schema-dsl 最佳实践
2
2
 
3
3
  > **用途**: 帮助你写出高质量、高性能的 Schema 代码
4
- > **更新**: 2025-12-26
4
+ > **更新**: 2026-05-08
5
5
 
6
6
  ---
7
7
 
@@ -33,7 +33,7 @@ const schema = dsl({
33
33
  **不推荐**(过度复杂):
34
34
  ```javascript
35
35
  const schema = dsl({
36
- username: dsl('string').minLength(3).maxLength(32).required(),
36
+ username: dsl('string').min(3).max(32).required(),
37
37
  // 太冗长了!
38
38
  });
39
39
  ```
@@ -67,9 +67,8 @@ const schema = dsl({
67
67
  }),
68
68
 
69
69
  email: 'email!'
70
- .custom(async (value) => {
71
- const exists = await checkEmailExists(value);
72
- if (exists) return '邮箱已被占用';
70
+ .custom((value) => {
71
+ if (value.endsWith('@blocked.example')) return '该邮箱域名不允许注册';
73
72
  })
74
73
  .label('邮箱地址')
75
74
  });
@@ -79,7 +78,7 @@ const schema = dsl({
79
78
 
80
79
  ### 3. 使用预设验证器
81
80
 
82
- SchemaI-DSL 提供了常用的预设验证器,开箱即用:
81
+ schema-dsl 提供了常用的预设验证器,开箱即用:
83
82
 
84
83
  ```javascript
85
84
  const schema = dsl({
@@ -164,6 +163,7 @@ app.post('/api/user', (req, res) => {
164
163
  **推荐**(预编译):
165
164
  ```javascript
166
165
  // 在应用启动时编译一次
166
+ const validator = new Validator();
167
167
  const userSchema = dsl({ username: 'string!' });
168
168
  const validateUser = validator.compile(userSchema);
169
169
 
@@ -172,15 +172,24 @@ app.post('/api/user', (req, res) => {
172
172
  });
173
173
  ```
174
174
 
175
- **性能提升**: 预编译可以提升 **10-100 倍** 的性能!
175
+ **收益**: 复用已编译结果可以显著减少重复编译成本,尤其适合热点路由和高频校验路径。
176
176
 
177
177
  ---
178
178
 
179
179
  ### 2. 启用缓存
180
180
 
181
181
  ```javascript
182
- const validator = new Validator({
183
- cache: true // 启用编译缓存
182
+ const validator = new Validator({
183
+ cache: true // ✅ 简写:启用默认编译缓存配置
184
+ });
185
+
186
+ // 需要更细粒度时,使用对象配置
187
+ const tunedValidator = new Validator({
188
+ cache: {
189
+ enabled: true,
190
+ maxSize: 500,
191
+ ttl: 60 * 60 * 1000
192
+ }
184
193
  });
185
194
 
186
195
  // 或者使用全局单例(默认启用缓存)
@@ -205,10 +214,15 @@ records.forEach(record => {
205
214
 
206
215
  **推荐**(批量验证):
207
216
  ```javascript
208
- const result = validator.validateBatch(schema, records);
209
- // 一次性验证所有记录,性能更好
217
+ const { SchemaUtils, Validator } = require('schema-dsl');
218
+
219
+ const validator = new Validator();
220
+ const result = SchemaUtils.validateBatch(schema, records, validator.getAjv());
221
+ // 当你已经复用 Validator 底层 Ajv 实例时,这条路径适合批量校验
210
222
  ```
211
223
 
224
+ > ℹ️ 如果你确实要直接传入自己创建的 Ajv 实例,请先确保它已经注册了与 schema-dsl 生成 schema 匹配的格式和关键字;对大多数项目来说,直接复用 `validator.getAjv()` 更稳妥。
225
+
212
226
  ---
213
227
 
214
228
  ### 4. 优化正则表达式
@@ -312,13 +326,17 @@ return res.status(400).json({
312
326
  ### 3. 限制 Schema 复杂度
313
327
 
314
328
  ```javascript
315
- const validator = new Validator({
316
- maxNestingDepth: 10, // 限制嵌套深度
317
- maxSchemaSize: 10000 // 限制 Schema 大小(建议)
318
- });
329
+ const MAX_SCHEMA_SIZE = 10000;
330
+
331
+ if (JSON.stringify(schema).length > MAX_SCHEMA_SIZE) {
332
+ throw new Error('Schema 体积过大,建议拆分');
333
+ }
319
334
 
320
335
  // 在 validate 前检查
321
- DslBuilder.validateNestingDepth(schema, 10);
336
+ const depthCheck = DslBuilder.validateNestingDepth(schema, 10);
337
+ if (!depthCheck.valid) {
338
+ throw new Error(depthCheck.message);
339
+ }
322
340
  ```
323
341
 
324
342
  ---
@@ -394,7 +412,7 @@ const schema = dsl({
394
412
  ```
395
413
 
396
414
  **效果**:
397
- ```
415
+ ```text
398
416
  ❌ 用户名不能为空
399
417
  ❌ 用户名至少需要3个字符
400
418
  ✅ 清晰明了,用户友好
@@ -402,22 +420,33 @@ const schema = dsl({
402
420
 
403
421
  ---
404
422
 
405
- ### 3. 处理异步验证错误
423
+ ### 3. 处理外部异步校验错误
424
+
425
+ > `.custom()` 当前仅支持同步函数;涉及数据库、RPC、HTTP 等异步检查时,请在基础校验通过后于业务层单独执行。
406
426
 
407
427
  ```javascript
408
428
  const schema = dsl({
409
- email: 'email!'.custom(async (value) => {
410
- try {
411
- const exists = await checkEmailExists(value);
412
- if (exists) return '邮箱已被占用';
413
- } catch (error) {
414
- // 记录错误但不阻止验证
415
- console.error('Email check failed:', error);
416
- // 可以选择跳过此验证或返回提示
417
- return; // 跳过
418
- }
419
- })
429
+ email: 'email!'.label('邮箱地址')
420
430
  });
431
+
432
+ async function validateUser(data) {
433
+ const result = validate(schema, data);
434
+ if (!result.valid) return result;
435
+
436
+ try {
437
+ const exists = await checkEmailExists(data.email);
438
+ if (exists) {
439
+ return {
440
+ valid: false,
441
+ errors: [{ field: 'email', keyword: 'business', message: '邮箱已被占用' }]
442
+ };
443
+ }
444
+ } catch (error) {
445
+ console.error('Email check failed:', error);
446
+ }
447
+
448
+ return result;
449
+ }
421
450
  ```
422
451
 
423
452
  ---
@@ -427,7 +456,7 @@ const schema = dsl({
427
456
  ### 1. 集中管理 Schema
428
457
 
429
458
  **推荐的项目结构**:
430
- ```
459
+ ```text
431
460
  src/
432
461
  ├── schemas/
433
462
  │ ├── index.js # 导出所有 Schema
@@ -498,25 +527,27 @@ router.post('/register', (req, res) => {
498
527
 
499
528
  ### 2. Schema 复用
500
529
 
501
- **使用 SchemaHelper**:
530
+ **使用 SchemaUtils**:
502
531
  ```javascript
503
- const { SchemaHelper } = require('schema-dsl');
532
+ const { SchemaUtils, dsl } = require('schema-dsl');
504
533
 
505
534
  // 创建可复用字段库
506
- const fields = SchemaHelper.createLibrary({
507
- email: 'email!',
508
- phone: dsl('string!').phone('cn'),
509
- password: dsl('string!').password('strong')
535
+ const fields = SchemaUtils.createLibrary({
536
+ email: () => 'email!',
537
+ phone: () => dsl('string!').phone('cn'),
538
+ password: () => dsl('string!').password('strong')
510
539
  });
511
540
 
512
541
  // 在多个 Schema 中复用
513
542
  const registerSchema = dsl({
514
- ...fields.pick(['email', 'password']),
543
+ email: fields.email(),
544
+ password: fields.password(),
515
545
  username: 'string:3-32!'
516
546
  });
517
547
 
518
548
  const profileSchema = dsl({
519
- ...fields.pick(['email', 'phone']),
549
+ email: fields.email(),
550
+ phone: fields.phone(),
520
551
  bio: 'string:500'
521
552
  });
522
553
  ```
@@ -535,12 +566,16 @@ const config = {
535
566
  development: {
536
567
  verbose: true,
537
568
  allErrors: true,
538
- cache: false // 开发时不缓存,便于调试
569
+ cache: false // ✅ 简写:关闭缓存,便于调试
539
570
  },
540
571
  production: {
541
572
  verbose: false,
542
573
  allErrors: false, // 只返回第一个错误
543
- cache: true // 生产环境启用缓存
574
+ cache: {
575
+ enabled: true,
576
+ maxSize: 1000,
577
+ ttl: 60 * 60 * 1000
578
+ }
544
579
  }
545
580
  };
546
581
 
@@ -601,7 +636,7 @@ app.get('/health', (req, res) => {
601
636
  res.json({
602
637
  status: 'ok',
603
638
  validator: 'operational',
604
- cacheSize: validator.getCacheSize()
639
+ cacheStats: validator.getCacheStats()
605
640
  });
606
641
  } catch (error) {
607
642
  res.status(500).json({
@@ -639,23 +674,21 @@ setInterval(() => {
639
674
 
640
675
  ## 性能基准参考
641
676
 
642
- 基于 SchemaI-DSL 的性能测试:
677
+ 缓存命中前后通常能显著降低重复编译开销,但绝对耗时会受到机器性能、Node 版本、schema 复杂度、数据规模和命中率影响,不建议把某组固定毫秒数当成通用基准。
678
+
679
+ **更稳定的结论**:
643
680
 
644
- | 操作 | 性能指标 |
645
- |------|---------|
646
- | 简单验证(未缓存) | ~0.1ms |
647
- | 简单验证(已缓存) | ~0.01ms |
648
- | 复杂嵌套(未缓存) | ~1ms |
649
- | 复杂嵌套(已缓存) | ~0.1ms |
650
- | 批量验证(1000条) | ~100ms |
681
+ - 复用同一个 schema 对象或 `Validator` 实例,通常比每次请求都重新编译更快
682
+ - schema 越复杂、重复验证次数越多,缓存收益通常越明显
683
+ - 批量验证总耗时主要取决于单条 schema 复杂度和数据规模,不应使用固定毫秒数做容量承诺
651
684
 
652
- **结论**: 合理使用缓存可以提升 **10-100倍** 性能。
685
+ 如需当前可复查的吞吐量对比,请以维护中的 benchmark 结果和 FAQ 中同步的性能数据为准。
653
686
 
654
687
  ---
655
688
 
656
689
  ## 总结
657
690
 
658
- 遵循这些最佳实践,你的 SchemaI-DSL 代码将具备:
691
+ 遵循这些最佳实践,你的 schema-dsl 代码将具备:
659
692
 
660
693
  ✅ **高性能** - 通过预编译和缓存
661
694
  ✅ **高安全性** - 避免常见安全陷阱
@@ -666,7 +699,14 @@ setInterval(() => {
666
699
 
667
700
  ## 延伸阅读
668
701
 
669
- - [性能优化指南](performance-guide.md)(待创建)
670
- - [安全检查清单](security-checklist.md)(待创建)
702
+ - [性能优化指南](performance-guide.md)
703
+ - [安全检查清单](security-checklist.md)
671
704
  - [故障排查指南](troubleshooting.md)
672
705
 
706
+ ---
707
+
708
+ ## 对应示例文件
709
+
710
+ **示例入口**: [best-practices.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/best-practices.ts)
711
+ **说明**: 展示“简单字段用纯 DSL、复杂字段局部使用 Builder、字段库复用”的推荐组合,以及成功 / 失败两条验证路径。
712
+
@@ -1,6 +1,6 @@
1
1
  # CacheManager 缓存管理器
2
2
 
3
- > **模块**: `lib/core/CacheManager.js`
3
+ > **模块**: `src/core/CacheManager.ts`(公开导出:`require('schema-dsl').CacheManager`)
4
4
 
5
5
  > **用途**: 高性能 Schema 编译缓存,支持 LRU 淘汰和 TTL 过期
6
6
 
@@ -19,7 +19,7 @@
19
19
 
20
20
  ## 概述
21
21
 
22
- `CacheManager` 是 SchemaI-DSL 的内部缓存系统,用于缓存编译后的 Schema 验证函数,避免重复编译带来的性能开销。
22
+ `CacheManager` 是 schema-dsl 的内部缓存系统,用于缓存编译后的 Schema 验证函数,避免重复编译带来的性能开销。
23
23
 
24
24
  ### 核心功能
25
25
 
@@ -34,11 +34,11 @@
34
34
  ## 快速开始
35
35
 
36
36
  ```javascript
37
- const CacheManager = require('schema-dsl/lib/core/CacheManager');
37
+ const { CacheManager } = require('schema-dsl');
38
38
 
39
39
  // 创建缓存实例
40
40
  const cache = new CacheManager({
41
- maxSize: 100, // 最大缓存数量
41
+ maxSize: 5000, // 默认最大缓存数量
42
42
  ttl: 3600000 // 1小时过期
43
43
  });
44
44
 
@@ -71,7 +71,7 @@ new CacheManager(options)
71
71
 
72
72
  | 参数 | 类型 | 默认值 | 说明 |
73
73
  |------|------|--------|------|
74
- | `options.maxSize` | number | `100` | 最大缓存条目数 |
74
+ | `options.maxSize` | number | `5000` | 最大缓存条目数 |
75
75
  | `options.ttl` | number | `3600000` | 缓存生存时间(毫秒) |
76
76
  | `options.enabled` | boolean | `true` | 是否启用缓存 |
77
77
  | `options.statsEnabled` | boolean | `true` | 是否启用统计 |
@@ -162,9 +162,10 @@ console.log(stats);
162
162
  // sets: 100, // 设置次数
163
163
  // deletes: 5, // 删除次数
164
164
  // clears: 1, // 清空次数
165
- // hitRate: 0.833, // 命中率 (83.3%)
165
+ // hitRate: '83.33', // 命中率百分比字符串
166
166
  // size: 80, // 当前缓存数量
167
- // maxSize: 100 // 最大容量
167
+ // maxSize: 5000, // 最大容量
168
+ // enabled: true // 是否启用缓存
168
169
  // }
169
170
  ```
170
171
 
@@ -180,12 +181,12 @@ cache.resetStats();
180
181
 
181
182
  ---
182
183
 
183
- ### `getSize()`
184
+ ### `size()`
184
185
 
185
186
  获取当前缓存条目数量。
186
187
 
187
188
  ```javascript
188
- console.log(`当前缓存: ${cache.getSize()} 条`);
189
+ console.log(`当前缓存: ${cache.size()} 条`);
189
190
  ```
190
191
 
191
192
  ---
@@ -235,12 +236,12 @@ function analyzeCachePerformance(cache) {
235
236
  console.log('=== 缓存性能分析 ===');
236
237
  console.log(`命中次数: ${stats.hits}`);
237
238
  console.log(`未命中次数: ${stats.misses}`);
238
- console.log(`命中率: ${(stats.hitRate * 100).toFixed(1)}%`);
239
+ console.log(`命中率: ${stats.hitRate}%`);
239
240
  console.log(`缓存使用率: ${(stats.size / stats.maxSize * 100).toFixed(1)}%`);
240
241
  console.log(`淘汰次数: ${stats.evictions}`);
241
242
 
242
243
  // 性能建议
243
- if (stats.hitRate < 0.5) {
244
+ if (Number(stats.hitRate) < 50) {
244
245
  console.log('⚠️ 命中率较低,考虑增加缓存大小');
245
246
  }
246
247
  if (stats.evictions > stats.sets * 0.5) {
@@ -254,13 +255,13 @@ function analyzeCachePerformance(cache) {
254
255
  ```javascript
255
256
  function printCacheDashboard(cache) {
256
257
  const stats = cache.getStats();
257
- const hitRate = (stats.hitRate * 100).toFixed(1);
258
+ const hitRate = `${stats.hitRate}%`;
258
259
  const usage = (stats.size / stats.maxSize * 100).toFixed(1);
259
260
 
260
261
  console.log('┌─────────────────────────────┐');
261
262
  console.log('│ 缓存状态仪表板 │');
262
263
  console.log('├─────────────────────────────┤');
263
- console.log(`│ 命中率: ${hitRate.padStart(6)}% │`);
264
+ console.log(`│ 命中率: ${hitRate.padStart(8)} │`);
264
265
  console.log(`│ 使用率: ${usage.padStart(6)}% │`);
265
266
  console.log(`│ 当前条目: ${String(stats.size).padStart(6)} │`);
266
267
  console.log(`│ 最大容量: ${String(stats.maxSize).padStart(6)} │`);
@@ -293,7 +294,7 @@ const cache = new CacheManager({
293
294
  ```javascript
294
295
  setInterval(() => {
295
296
  const stats = cache.getStats();
296
- if (stats.hitRate < 0.8) {
297
+ if (Number(stats.hitRate) < 80) {
297
298
  console.warn('缓存命中率低于80%');
298
299
  }
299
300
  }, 60000);
@@ -317,7 +318,7 @@ function updateSchema(name, newSchema) {
317
318
 
318
319
  当缓存达到最大容量时,自动淘汰最久未使用的条目:
319
320
 
320
- ```
321
+ ```text
321
322
  缓存操作顺序:
322
323
  1. set('A', ...) → [A]
323
324
  2. set('B', ...) → [A, B]
@@ -334,3 +335,10 @@ function updateSchema(name, newSchema) {
334
335
  - [性能优化指南](validation-guide.md#性能优化)
335
336
  - [API 参考](api-reference.md)
336
337
 
338
+ ---
339
+
340
+ ## 对应示例文件
341
+
342
+ **示例入口**: [cache-manager.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/cache-manager.ts)
343
+ **说明**: 覆盖 `set/get/has`、LRU 淘汰、统计信息读取和 `resetStats()` 的实际行为。
344
+
@@ -0,0 +1,45 @@
1
+ # compile 方法
2
+
3
+ `Validator.compile(schema, cacheKey?)` 会将 JSON Schema 编译为 AJV 验证函数,并在传入 `cacheKey` 时复用缓存。
4
+
5
+ ## 方法签名
6
+
7
+ ```javascript
8
+ validator.compile(schema, cacheKey?)
9
+ ```
10
+
11
+ ## 参数
12
+
13
+ - `schema` - JSON Schema 对象
14
+ - `cacheKey` - 可选缓存键;传入后,同一个 `Validator` 实例内可复用已编译结果
15
+
16
+ ## 返回值
17
+
18
+ 返回 AJV 验证函数,可直接像普通函数一样调用;执行结果为 `true / false`,错误详情挂在 `validate.errors` 上。
19
+
20
+ ```javascript
21
+ const { Validator, dsl } = require('schema-dsl');
22
+ const validator = new Validator();
23
+ const schema = dsl({ name: 'string!' });
24
+ const validate = validator.compile(schema, 'user-schema');
25
+ console.log(validate({ name: 'Rocky' }));
26
+ ```
27
+
28
+ ## 适用场景
29
+
30
+ - 同一份 schema 需要重复校验多次时,先 `compile()` 再复用编译结果
31
+ - 需要自己控制缓存键,避免重复编译开销
32
+ - 想把编译和执行拆开,接入自定义流程
33
+
34
+ ## 注意事项
35
+
36
+ - `cacheKey` 的缓存作用域是当前 `Validator` 实例,不跨实例共享
37
+ - 如果只是对同一份 schema 做批量校验,也可以直接使用 `validator.validateBatch()`
38
+
39
+ ---
40
+
41
+ ## 对应示例文件
42
+
43
+ **示例入口**: [compile.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/compile.ts)
44
+ **说明**: 覆盖 `compile()` 的编译结果复用、`cacheKey` 命中,以及失败场景下从验证函数读取错误详情。
45
+
@@ -1,7 +1,7 @@
1
1
  # 链式条件 API - ConditionalBuilder
2
2
 
3
- > **版本**: v1.1.1
4
- > **更新日期**: 2026-01-06
3
+ > **版本**: schema-dsl v2.0.0-beta.2
4
+ > **更新日期**: 2026-05-08
5
5
  > **状态**: ✅ 稳定
6
6
 
7
7
  ---
@@ -22,6 +22,8 @@
22
22
 
23
23
  `ConditionalBuilder` 提供流畅的链式条件判断 API,类似 JavaScript 的 if-else 语句,用于在验证时根据实际数据动态调整验证规则。
24
24
 
25
+ > 关键语义:当你使用 `.message()` / `.assert()` / `.check()` 这类“失败即返回”的模式时,条件函数应该写成**失败条件**,因为条件返回 `true` 才会被判定为失败。
26
+
25
27
  ### 核心特性
26
28
 
27
29
  - ✅ **链式调用** - 流畅的 API,类似 JavaScript if-else
@@ -218,21 +220,21 @@ const { dsl, validate } = require('schema-dsl');
218
220
  // 方式1:传统方式(需要 validate 函数)
219
221
  const schema1 = dsl({
220
222
  age: 'number!',
221
- status: dsl.if((data) => data.age >= 18)
223
+ status: dsl.if((data) => data.age < 18)
222
224
  .message('未成年用户不能注册')
223
225
  });
224
226
 
225
227
  validate(schema1, { age: 16, status: 'active' });
226
- // => { valid: false, errors: [{ message: '未成年用户不能注册' }] }
228
+ // => { valid: false, errors: [{ message: '未成年用户不能注册' }], data: { age: 16, status: 'active' } }
227
229
 
228
230
  // ✅ 方式2:快捷方式(一行代码验证)
229
- const result = dsl.if((data) => data.age >= 18)
231
+ const result = dsl.if((data) => data.age < 18)
230
232
  .message('未成年用户不能注册')
231
233
  .validate({ age: 16 });
232
- // => { valid: false, errors: [{ message: '未成年用户不能注册' }] }
234
+ // => { valid: false, errors: [{ message: '未成年用户不能注册' }], data: { age: 16 } }
233
235
 
234
236
  // ✅ 方式3:.check() 快速判断
235
- const isValid = dsl.if((data) => data.age >= 18)
237
+ const isValid = dsl.if((data) => data.age < 18)
236
238
  .message('未成年用户不能注册')
237
239
  .check({ age: 16 });
238
240
  // => false
@@ -421,6 +423,26 @@ dsl.if(d => d.age < 18)
421
423
 
422
424
  ---
423
425
 
426
+ ### .build()
427
+
428
+ 将当前 `ConditionalBuilder` 输出为可直接交给 `Validator` / `validate()` 使用的 schema 对象。
429
+
430
+ `.build()` 是 `.toSchema()` 的别名,适合在你想显式拿到最终 schema 时使用。
431
+
432
+ ```javascript
433
+ const { dsl, validate } = require('schema-dsl');
434
+
435
+ const conditionalSchema = dsl.if(data => data.age >= 18)
436
+ .then('email!')
437
+ .else('email')
438
+ .build();
439
+
440
+ const result = validate(conditionalSchema, 'user@example.com');
441
+ console.log(result.valid);
442
+ ```
443
+
444
+ ---
445
+
424
446
  ### .elseIf(condition)
425
447
 
426
448
  添加 else-if 分支。
@@ -458,11 +480,11 @@ dsl.if((data) => data.userType === 'admin')
458
480
 
459
481
  **基础示例**:
460
482
  ```javascript
461
- dsl.if((data) => data.age >= 18)
483
+ dsl.if((data) => data.age < 18)
462
484
  .message('未成年用户不能注册')
463
485
 
464
486
  // 支持多语言 key
465
- dsl.if((data) => data.age >= 18)
487
+ dsl.if((data) => data.age < 18)
466
488
  .message('error.underage')
467
489
  ```
468
490
 
@@ -666,7 +688,7 @@ try {
666
688
 
667
689
  **返回**: `*` - 验证通过返回数据
668
690
 
669
- **抛出**: `Error` - 验证失败抛出错误(name: 'ValidationError')
691
+ **抛出**: `ValidationError` - 验证失败时直接抛出 `ValidationError`
670
692
 
671
693
  **特性**: 同步版本的断言验证,适合快速失败场景
672
694
 
@@ -1237,7 +1259,7 @@ validate(contactSchema, 'user@example.com'); // ✅ 作为邮箱验证
1237
1259
  validate(contactSchema, '13800138000'); // ✅ 作为手机号验证
1238
1260
  ```
1239
1261
 
1240
- **完整示例**: 参见 `examples/conditional-non-object.js`
1262
+ **完整示例**: 参见 `test/unit/conditional-non-object.test.ts`
1241
1263
 
1242
1264
  ---
1243
1265
 
@@ -1276,3 +1298,10 @@ validate(contactSchema, '13800138000'); // ✅ 作为手机号验证
1276
1298
  - [API 参考](./api-reference.md)
1277
1299
  - [最佳实践](./best-practices.md)
1278
1300
 
1301
+ ---
1302
+
1303
+ ## 对应示例文件
1304
+
1305
+ **示例入口**: [conditional-api.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/conditional-api.ts)
1306
+ **说明**: 同时覆盖失败谓词模式下的 `.check()` / `.assert()`,以及字段名版本 `dsl.if(field, then, else)` 和 `dsl.match()` 映射。
1307
+