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
@@ -0,0 +1,34 @@
1
+ # 自定义类型注册
2
+
3
+ 当前版本通过 `TypeRegistry` 提供类型注册能力;如果你更偏向 DSL 侧入口,也可以使用 `DslBuilder.registerType()`,它内部会委托给 `TypeRegistry`。
4
+
5
+ ```javascript
6
+ const { TypeRegistry, dsl } = require('schema-dsl');
7
+
8
+ TypeRegistry.register('evenNumber', {
9
+ baseSchema: { type: 'number', multipleOf: 2 }
10
+ });
11
+
12
+ const schema = dsl({ value: 'evenNumber!' });
13
+ ```
14
+
15
+ 如果你希望统一从 Builder 侧管理自定义类型,也可以这样写:
16
+
17
+ ```javascript
18
+ const { DslBuilder } = require('schema-dsl');
19
+
20
+ DslBuilder.registerType('orderCode', {
21
+ type: 'string',
22
+ pattern: '^ORD\\d{6}$'
23
+ });
24
+ ```
25
+
26
+ 插件化扩展可结合 [plugin-system.md](./plugin-system.md) 使用。
27
+
28
+ ---
29
+
30
+ ## 对应示例文件
31
+
32
+ **示例入口**: [plugin-type-registration.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/plugin-type-registration.ts)
33
+ **说明**: 同时覆盖 `TypeRegistry.register()` 和 `DslBuilder.registerType()` 两条入口,以及注册后的真实验证与清理流程。
34
+
@@ -1,6 +1,6 @@
1
1
  # PostgreSQL 导出器文档
2
2
 
3
- > **模块**: `lib/exporters/PostgreSQLExporter.js`
3
+ > **模块**: `src/exporters/PostgreSQLExporter.ts`
4
4
 
5
5
  > **用途**: 将 JSON Schema 转换为 PostgreSQL CREATE TABLE 语句
6
6
 
@@ -20,7 +20,7 @@
20
20
 
21
21
  ## 概述
22
22
 
23
- `PostgreSQLExporter` 将 SchemaI-DSL 生成的 JSON Schema 转换为 PostgreSQL 的 DDL 语句,支持丰富的 PostgreSQL 特性。
23
+ `PostgreSQLExporter` 将 schema-dsl 生成的 JSON Schema 转换为 PostgreSQL 的 DDL 语句,支持丰富的 PostgreSQL 特性。
24
24
 
25
25
  ### 核心功能
26
26
 
@@ -302,3 +302,10 @@ exporter.generateIndex('users', 'metadata', { method: 'gin' });
302
302
  - [TypeConverter](type-converter.md)
303
303
  - [**导出限制说明**](export-limitations.md) ⚠️
304
304
 
305
+ ---
306
+
307
+ ## 对应示例文件
308
+
309
+ **示例入口**: [postgresql-exporter.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/postgresql-exporter.ts)
310
+ **说明**: 覆盖 PostgreSQL DDL 导出、CHECK 约束示意,以及 `generateIndex()` 生成 `gin` 索引。
311
+
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
2
+ <rect width="64" height="64" rx="14" fill="#0F172A" />
3
+ <path d="M18 22.5L32 14L46 22.5V41.5L32 50L18 41.5V22.5Z" fill="#38BDF8" />
4
+ <path d="M32 20L40 24.8V34.2L32 39L24 34.2V24.8L32 20Z" fill="#E2E8F0" />
5
+ </svg>
@@ -28,6 +28,10 @@
28
28
  npm install schema-dsl
29
29
  ```
30
30
 
31
+ > **Node.js 要求**:`>=18.0.0`
32
+ >
33
+ > 当前 TypeScript 重构版以 `Node.js >=18.0.0` 为唯一运行时基线,不再承诺旧 Node 版本兼容。
34
+
31
35
  ---
32
36
 
33
37
  ## 📖 5分钟快速入门
@@ -135,34 +139,32 @@ const schema = dsl({
135
139
  ### 4. 完整示例(2分钟)
136
140
 
137
141
  ```javascript
138
- const { dsl, Validator } = require('schema-dsl');
142
+ const { dsl, validate } = require('schema-dsl');
139
143
 
140
144
  // 定义用户注册Schema
141
145
  const registerSchema = dsl({
142
146
  // 用户名:正则验证
143
- username: 'string:3-32!'
147
+ username: dsl('string:3-32!')
144
148
  .pattern(/^[a-zA-Z0-9_]+$/)
145
149
  .label('用户名')
146
- .messages({
147
- 'pattern': '只能包含字母、数字和下划线',
148
- 'min': '至少3个字符',
149
- 'max': '最多32个字符'
150
+ .error({
151
+ pattern: '只能包含字母、数字和下划线'
150
152
  }),
151
153
 
152
154
  // 邮箱:标签
153
- email: 'email!'.label('邮箱地址'),
155
+ email: dsl('email!').label('邮箱地址'),
154
156
 
155
157
  // 密码:复杂正则
156
- password: 'string:8-64!'
158
+ password: dsl('string:8-64!')
157
159
  .pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$/)
158
160
  .label('密码')
159
- .messages({
160
- 'pattern': '必须包含大小写字母和数字'
161
+ .error({
162
+ pattern: '必须包含大小写字母和数字'
161
163
  }),
162
164
 
163
165
  // 简单字段
164
166
  age: 'number:18-120',
165
- gender: 'male|female|other'
167
+ role: 'user|admin'
166
168
  });
167
169
 
168
170
  // 验证数据
@@ -171,7 +173,7 @@ const testData = {
171
173
  email: 'john@example.com',
172
174
  password: 'Password123',
173
175
  age: 25,
174
- gender: 'male'
176
+ role: 'user'
175
177
  };
176
178
 
177
179
  const result = validate(registerSchema, testData);
@@ -236,12 +238,13 @@ const formSchema = dsl({
236
238
 
237
239
  ### 自定义验证
238
240
 
241
+ > `.custom()` 当前仅支持同步函数;如果需要异步查重,请在 `validate()` / `validateAsync()` 通过后于业务层单独执行。
242
+
239
243
  ```javascript
240
244
  const schema = dsl({
241
245
  username: 'string:3-32!'
242
- .custom(async (value) => {
243
- const exists = await checkUsernameExists(value);
244
- if (exists) {
246
+ .custom((value) => {
247
+ if (value === 'admin') {
245
248
  return '用户名已存在';
246
249
  }
247
250
  })
@@ -277,9 +280,9 @@ const schema = dsl({
277
280
 
278
281
  ### 示例代码
279
282
 
280
- - [String扩展完整示例](../examples/string-extensions.js)
281
- - [用户注册示例](../examples/user-registration/)
282
- - [数据库导出示例](../examples/export-demo.js)
283
+ - [Quick Start 完整示例](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/quick-start.ts)
284
+
285
+ 其余主题示例现在都已分别挂到各自文档底部,并统一切到稳定 GitHub 示例链接。
283
286
 
284
287
  ### 高级功能
285
288
 
@@ -344,31 +347,20 @@ Schema-DSL 使用**运行时解析 DSL**,而非编译时构建(如 Zod),
344
347
 
345
348
  #### ⚠️ 性能权衡
346
349
 
347
- 运行时解析的代价是性能略低于编译时构建:
350
+ S1 有效数据与 Zod 持平,S3 嵌套场景快约 28%,无效数据公平对比快 89x:
348
351
 
349
- | 库名 | 每秒操作数 | 说明 |
352
+ | 库名 | 性能 | 场景 |
350
353
  |------|-----------|------|
351
- | Ajv | 2,000,000 ops/s | 原生 JSON Schema(最快) |
352
- | Zod | 526,316 ops/s | 编译时构建 |
353
- | **Schema-DSL** | **277,778 ops/s** | 运行时解析(第3名) |
354
- | Joi | 97,087 ops/s | 功能丰富 |
355
- | Yup | 60,241 ops/s | React 生态 |
354
+ | Ajv (raw) | 4.732M ops/s | 底层引擎,无 DSL |
355
+ | **Schema-DSL** | **1.301M ops/s**(S1有效) | 全功能(DSL + i18n + coerce)|
356
+ | **Schema-DSL** | **1.205M ops/s**(S2 无效,均无 i18n)| 公平对比(均无 i18n)|
357
+ | Zod | 1.305M ops/s(S1有效)/ 13.49K(S2 无效)| 编译时构建,错误路径异常驱动 |
358
+ | Joi | 154K ops/s | 功能丰富 |
356
359
 
357
360
  **结论**:
358
- - ✅ Schema-DSL Joi 快 **2.86倍**,比 Yup 快 **4.61倍**
359
- - ✅ 对大多数应用足够(27万+ ops/s)
360
- - ⚠️ 如需极致性能(>50万 ops/s),推荐使用 Zod 或 Ajv
361
-
362
- **权衡**:
363
- ```
364
- 损失: 比 Zod 慢 1.9倍
365
- 换来:
366
- ✅ 代码量减少 65%
367
- ✅ 完全动态的验证规则
368
- ✅ 多租户/配置驱动支持
369
- ✅ 前后端共享规则
370
- ✅ 低代码平台基础
371
- ```
361
+ - ✅ S3 嵌套有效场景比 Zod 快 **28%**;S1 简单有效场景持平(差 <1%)
362
+ - ✅ 无效数据公平对比(均无 i18n)比 Zod 快 **89x**
363
+ - 内置缓存,热路径零解析开销
372
364
 
373
365
  ### 适用场景
374
366
 
@@ -413,13 +405,13 @@ uninstallStringExtensions();
413
405
 
414
406
  ### Q: 支持TypeScript吗?
415
407
 
416
- **A**: 支持!SchemaI-DSL提供完整的TypeScript类型定义。
408
+ **A**: 支持!schema-dsl 提供完整的 TypeScript 类型定义。
417
409
 
418
410
  ---
419
411
 
420
412
  ## 🎉 恭喜!
421
413
 
422
- 你已经掌握了SchemaI-DSL的核心用法!
414
+ 你已经掌握了 schema-dsl 的核心用法!
423
415
 
424
416
  **核心要点**:
425
417
  1. ✅ DSL语法简洁直观
@@ -431,331 +423,13 @@ uninstallStringExtensions();
431
423
 
432
424
  ---
433
425
 
434
- ---
435
-
436
- **最后更新**: 2025-12-26
437
- - [🔧 自定义验证](#-自定义验证)
438
- - [🗄️ 数据库导出](#️-数据库导出)
439
- - [📚 下一步](#-下一步)
440
-
441
- ---
442
-
443
- ## 🚀 安装
444
-
445
- ```bash
446
- npm install schema-dsl
447
- ```
448
-
449
- ---
450
-
451
- ## 📖 5分钟快速入门
452
-
453
- ### 1. Hello World(30秒)
454
-
455
- ```javascript
456
- const { dsl, Validator } = require('schema-dsl');
457
-
458
- // 定义Schema
459
- const schema = dsl({
460
- name: 'string:1-50!',
461
- email: 'email!'
462
- });
463
-
464
- // 验证数据
465
- const validator = new Validator();
466
- const result = validator.validate(schema, {
467
- name: '张三',
468
- email: 'zhangsan@example.com'
469
- });
470
-
471
- console.log(result.valid); // true
472
- ```
473
-
474
- **解释**:
475
- - `'string:1-50!'` - 必填字符串,长度1-50
476
- - `'email!'` - 必填邮箱
477
- - `!` 表示必填
478
-
479
- ---
480
-
481
- ### 2. DSL 语法速查(1分钟)
482
-
483
- ```javascript
484
- // 基本类型
485
- 'string' // 字符串
486
- 'number' // 数字
487
- 'integer' // 整数
488
- 'boolean' // 布尔值
489
- 'email' // 邮箱
490
- 'url' // URL
491
- 'date' // 日期
492
-
493
- // 约束
494
- 'string:3-32' // 长度3-32(范围)
495
- 'string:100' // 最大长度100(简写)
496
- 'string:-100' // 最大长度100(明确写法)
497
- 'string:10-' // 最小长度10(无最大限制)
498
- 'number:18-120' // 范围18-120
499
-
500
- // 必填
501
- 'string!' // 必填字符串
502
- 'email!' // 必填邮箱
503
-
504
- // 枚举
505
- 'active|inactive|pending' // 三选一
506
-
507
- // 数组
508
- 'array<string>' // 字符串数组
509
- 'array:1-10<string>' // 1-10个字符串
510
- 'array<string:1-50>' // 带约束的数组元素
511
- ```
512
-
513
- **语法规则**:
514
- - `type:max` → 最大值(简写)
515
- - `type:min-max` → 范围
516
- - `type:min-` → 只限最小
517
- - `type:-max` → 只限最大
518
-
519
- ---
520
-
521
- ### 3. String 扩展 - 核心特性(2分钟)
522
-
523
- 字符串支持链式调用:
426
+ ## 对应示例文件
524
427
 
525
- ```javascript
526
- const schema = dsl({
527
- // ✨ 字符串直接链式调用,无需 dsl() 包裹
528
- email: 'email!'
529
- .pattern(/custom/)
530
- .label('邮箱地址'),
531
-
532
- username: 'string:3-32!'
533
- .pattern(/^[a-zA-Z0-9_]+$/)
534
- .messages({
535
- 'string.pattern': '只能包含字母、数字和下划线'
536
- })
537
- .label('用户名'),
538
-
539
- // 简单字段仍然可以用纯DSL
540
- age: 'number:18-120',
541
- role: 'user|admin'
542
- });
543
- ```
544
-
545
- **可用方法**:
546
- - `.pattern(regex)` - 正则验证
547
- - `.label(text)` - 字段标签
548
- - `.messages(obj)` - 自定义消息
549
- - `.description(text)` - 描述
550
- - `.custom(fn)` - 自定义验证器
428
+ **示例入口**: [quick-start.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/quick-start.ts)
429
+ **说明**: 覆盖快速上手中的 Hello World、String 扩展、用户注册示例,以及 `validate()` 与 `Validator.compile()` 的基础复用路径,可直接运行参考。
551
430
 
552
431
  ---
553
432
 
554
- ### 4. 完整示例(2分钟)
555
-
556
- ```javascript
557
- const { dsl, validate } = require('schema-dsl');
558
-
559
- // 定义用户注册Schema
560
- const registerSchema = dsl({
561
- // 用户名:正则验证
562
- username: 'string:3-32!'
563
- .pattern(/^[a-zA-Z0-9_]+$/)
564
- .label('用户名')
565
- .messages({
566
- 'pattern': '只能包含字母、数字和下划线',
567
- 'min': '至少3个字符',
568
- 'max': '最多32个字符'
569
- }),
570
-
571
- // 邮箱:标签
572
- email: 'email!'.label('邮箱地址'),
573
-
574
- // 密码:复杂正则
575
- password: 'string:8-64!'
576
- .pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$/)
577
- .label('密码')
578
- .messages({
579
- 'pattern': '必须包含大小写字母和数字'
580
- }),
581
-
582
- // 简单字段
583
- age: 'number:18-120',
584
- gender: 'male|female|other'
585
- });
586
-
587
- // 验证数据
588
- const testData = {
589
- username: 'john_doe',
590
- email: 'john@example.com',
591
- password: 'Password123',
592
- age: 25,
593
- gender: 'male'
594
- };
595
-
596
- const result = validate(registerSchema, testData);
597
-
598
- if (result.valid) {
599
- console.log('✅ 验证通过!');
600
- } else {
601
- console.log('❌ 验证失败:', result.errors);
602
- }
603
- ```
604
-
605
- ---
606
-
607
- ## 💡 最佳实践
608
-
609
- ### 1. 简单字段用纯DSL
610
-
611
- ```javascript
612
- const schema = dsl({
613
- name: 'string:1-50!', // ✅ 简洁
614
- age: 'number:18-120', // ✅ 清晰
615
- role: 'user|admin' // ✅ 直观
616
- });
617
- ```
618
-
619
- ### 2. 复杂字段用String扩展
620
-
621
- ```javascript
622
- const schema = dsl({
623
- email: 'email!'
624
- .pattern(/custom/)
625
- .messages({...})
626
- .label('邮箱'),
627
-
628
- username: 'string:3-32!'
629
- .pattern(/^\w+$/)
630
- .custom(checkExists)
631
- });
632
- ```
633
-
634
- ### 3. 80/20 法则
635
-
636
- **80%字段用纯DSL,20%字段用String扩展**
637
-
638
- ---
639
-
640
- ## 🎯 常见场景
641
-
642
- ### 表单验证
643
-
644
- ```javascript
645
- const formSchema = dsl({
646
- email: 'email!'.label('邮箱地址'),
647
- password: 'string:8-64!'.label('密码'),
648
- nickname: 'string:2-20'.label('昵称'),
649
- bio: 'string:500',
650
- website: 'url',
651
- age: 'number:18-120',
652
- gender: 'male|female|other'
653
- });
654
- ```
655
-
656
- ### 自定义验证
657
-
658
- ```javascript
659
- const schema = dsl({
660
- username: 'string:3-32!'
661
- .custom(async (value) => {
662
- const exists = await checkUsernameExists(value);
663
- if (exists) {
664
- return { error: 'username.exists', message: '用户名已存在' };
665
- }
666
- return true;
667
- })
668
- });
669
- ```
670
-
671
- ### 嵌套对象
672
-
673
- ```javascript
674
- const schema = dsl({
675
- user: {
676
- profile: {
677
- name: 'string:1-50!'.label('姓名'),
678
- avatar: 'url'.label('头像'),
679
- social: {
680
- twitter: 'url'.pattern(/twitter\.com/),
681
- github: 'url'.pattern(/github\.com/)
682
- }
683
- }
684
- }
685
- });
686
- ```
687
-
688
- ---
689
-
690
- ## 📚 下一步
691
-
692
- ### 深入学习
693
-
694
- - [DSL 语法完整指南](./dsl-syntax.md)
695
- - [API 参考文档](./api-reference.md)
696
- - [String 扩展文档](./string-extensions.md)
697
-
698
- ### 示例代码
699
-
700
- - [String扩展完整示例](../examples/string-extensions.js)
701
- - [用户注册示例](../examples/user-registration/)
702
- - [数据库导出示例](../examples/export-demo.js)
703
-
704
- ### 高级功能
705
-
706
- - [自定义验证器](./api-reference.md#custom)
707
- - [条件验证(when)](./api-reference.md#when)
708
- - [数据库Schema导出](./api-reference.md#导出器)
709
-
710
- ---
711
-
712
- ## 🆘 常见问题
713
-
714
- ### Q: String扩展和纯DSL有什么区别?
715
-
716
- **A**:
717
- - **纯DSL**: 适合简单字段,语法简洁
718
- - **String扩展**: 适合复杂验证,支持链式调用
719
-
720
- ```javascript
721
- // 纯DSL(简单)
722
- name: 'string:1-50!'
723
-
724
- // String扩展(复杂)
725
- email: 'email!'
726
- .pattern(/custom/)
727
- .messages({...})
728
- ```
729
-
730
- ### Q: 如何禁用String扩展?
731
-
732
- **A**:
733
- ```javascript
734
- const { uninstallStringExtensions } = require('schema-dsl');
735
- uninstallStringExtensions();
736
- ```
737
-
738
- ### Q: 支持TypeScript吗?
739
-
740
- **A**: 支持!SchemaI-DSL提供完整的TypeScript类型定义。
741
-
742
- ---
743
-
744
- ## 🎉 恭喜!
745
-
746
- 你已经掌握了SchemaI-DSL的核心用法!
747
-
748
- **核心要点**:
749
- 1. ✅ DSL语法简洁直观
750
- 2. ✅ String扩展强大灵活
751
- 3. ✅ 80%用DSL,20%用扩展
752
- 4. ✅ 字符串可以直接链式调用
753
-
754
- **开始使用**: `npm install schema-dsl`
755
-
756
- ---
757
-
758
-
759
- **最后更新**: 2025-12-25
433
+ **最后更新**: 2026-05-08
760
434
 
761
435
 
@@ -188,13 +188,17 @@ dsl.error.assert(
188
188
  ```javascript
189
189
  const { dsl } = require('schema-dsl');
190
190
 
191
+ function getRequestLocale(acceptLanguage) {
192
+ return acceptLanguage?.split(',')[0]?.trim() || 'zh-CN';
193
+ }
194
+
191
195
  // Express 中间件
192
196
  app.get('/api/account/:id', async (req, res, next) => {
193
197
  try {
194
198
  const account = await getAccount(req.params.id);
195
199
 
196
200
  // 根据请求头获取语言
197
- const locale = req.headers['accept-language'] || 'zh-CN';
201
+ const locale = getRequestLocale(req.headers['accept-language']);
198
202
 
199
203
  // 使用运行时语言抛出错误
200
204
  dsl.error.assert(account, 'account.notFound', {}, 404, locale);
@@ -236,7 +240,7 @@ async function getUserService(userId, locale) {
236
240
  // 服务 B: API 网关
237
241
  app.get('/api/users/:id', async (req, res) => {
238
242
  try {
239
- const locale = req.headers['accept-language'] || 'zh-CN';
243
+ const locale = getRequestLocale(req.headers['accept-language']);
240
244
 
241
245
  // 调用用户服务,传递 locale
242
246
  const user = await getUserService(req.params.id, locale);
@@ -343,7 +347,7 @@ const resolvers = {
343
347
  // ❌ 并发不安全
344
348
  app.get('/api/account/:id', async (req, res) => {
345
349
  // 修改全局状态
346
- Locale.setLocale(req.headers['accept-language']);
350
+ Locale.setLocale(req.headers['accept-language']?.split(',')[0]?.trim() || 'zh-CN');
347
351
 
348
352
  // 如果同时有多个请求,语言会互相干扰
349
353
  const error = dsl.error.create('account.notFound');
@@ -356,7 +360,7 @@ app.get('/api/account/:id', async (req, res) => {
356
360
  ```javascript
357
361
  // ✅ 并发安全
358
362
  app.get('/api/account/:id', async (req, res) => {
359
- const locale = req.headers['accept-language'];
363
+ const locale = req.headers['accept-language']?.split(',')[0]?.trim() || 'zh-CN';
360
364
 
361
365
  // 不修改全局状态,每个请求独立
362
366
  const error = dsl.error.create('account.notFound', {}, 404, locale);
@@ -422,7 +426,7 @@ console.log(error2.message); // "Insufficient balance, current: 50, required: 1
422
426
  ```javascript
423
427
  // ✅ 推荐
424
428
  app.get('/api/account/:id', async (req, res) => {
425
- const locale = req.headers['accept-language'] || 'zh-CN';
429
+ const locale = req.headers['accept-language']?.split(',')[0]?.trim() || 'zh-CN';
426
430
 
427
431
  try {
428
432
  const account = await getAccount(req.params.id);
@@ -435,7 +439,7 @@ app.get('/api/account/:id', async (req, res) => {
435
439
 
436
440
  // ❌ 不推荐
437
441
  app.get('/api/account/:id', async (req, res) => {
438
- Locale.setLocale(req.headers['accept-language']); // 并发不安全
442
+ Locale.setLocale(req.headers['accept-language']?.split(',')[0]?.trim() || 'zh-CN'); // 并发不安全
439
443
  // ...
440
444
  });
441
445
  ```
@@ -446,7 +450,7 @@ app.get('/api/account/:id', async (req, res) => {
446
450
  // 工具函数
447
451
  function getUserLocale(req) {
448
452
  return req.user?.locale ||
449
- req.headers['accept-language'] ||
453
+ req.headers['accept-language']?.split(',')[0]?.trim() ||
450
454
  'zh-CN';
451
455
  }
452
456
 
@@ -504,7 +508,7 @@ app.get('/api/users/:id', async (req, res) => {
504
508
  - 现有代码无需修改
505
509
  - `locale` 参数为可选参数
506
510
  - 不传 `locale` 时使用全局语言
507
- - 所有单元测试通过(949/949)
511
+ - 相关单元测试已覆盖
508
512
 
509
513
  ---
510
514
 
@@ -516,6 +520,13 @@ app.get('/api/users/:id', async (req, res) => {
516
520
 
517
521
  ---
518
522
 
519
- **最后更新**: 2026-01-13
523
+ ## 对应示例文件
524
+
525
+ **示例入口**: [runtime-locale-support.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/runtime-locale-support.ts)
526
+ **说明**: 覆盖运行时指定 locale 创建错误对象、参数插值,以及“局部语言切换不污染全局状态”的关键行为。
527
+
528
+ ---
529
+
530
+ **最后更新**: 2026-05-08
520
531
  **作者**: schema-dsl Team
521
532
 
@@ -1,6 +1,6 @@
1
1
  # SchemaHelper Schema辅助工具
2
2
 
3
- > **模块**: `lib/utils/SchemaHelper.js`
3
+ > **模块**: `src/utils/SchemaHelper.ts`
4
4
 
5
5
  > **用途**: 提供 JSON Schema 操作的常用辅助方法
6
6
 
@@ -36,8 +36,7 @@
36
36
  ## 快速开始
37
37
 
38
38
  ```javascript
39
- const { SchemaHelper } = require('schema-dsl/lib/utils');
40
- const { dsl } = require('schema-dsl');
39
+ const { SchemaHelper, dsl } = require('schema-dsl');
41
40
 
42
41
  // 创建 Schema
43
42
  const userSchema = dsl({
@@ -263,8 +262,7 @@ const summary = SchemaHelper.summarizeSchema(userSchema);
263
262
  ### Schema 分析工具
264
263
 
265
264
  ```javascript
266
- const { SchemaHelper } = require('schema-dsl/lib/utils');
267
- const { dsl } = require('schema-dsl');
265
+ const { SchemaHelper, dsl } = require('schema-dsl');
268
266
 
269
267
  function analyzeSchema(schema, name = 'Schema') {
270
268
  console.log(`\n=== ${name} 分析 ===`);
@@ -338,3 +336,10 @@ function compareSchemaVersions(oldSchema, newSchema) {
338
336
  - [SchemaUtils](schema-utils.md)
339
337
  - [API 参考](api-reference.md)
340
338
 
339
+ ---
340
+
341
+ ## 对应示例文件
342
+
343
+ **示例入口**: [schema-helper.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/schema-helper.ts)
344
+ **说明**: 覆盖 `isValidSchema()`、`generateSchemaId()`、`flattenSchema()`、`extractRequiredFields()`、`summarizeSchema()` 与 `compareSchemas()`。
345
+