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,503 +0,0 @@
1
- /**
2
- * ConditionalBuilder - 链式条件构建器
3
- *
4
- * 提供流畅的条件判断 API,类似 JavaScript if-else 语句
5
- *
6
- * @module lib/core/ConditionalBuilder
7
- * @version 1.0.0
8
- *
9
- * @example
10
- * // 简单条件 + 错误消息
11
- * dsl.if((data) => data.age >= 18)
12
- * .message('未成年用户不能注册')
13
- *
14
- * @example
15
- * // 多条件 and
16
- * dsl.if((data) => data.age >= 18)
17
- * .and((data) => data.userType === 'admin')
18
- * .then('email!')
19
- *
20
- * @example
21
- * // 多条件 or
22
- * dsl.if((data) => data.age < 18)
23
- * .or((data) => data.isBlocked)
24
- * .message('不允许注册')
25
- *
26
- * @example
27
- * // elseIf 和 else
28
- * dsl.if((data) => data.userType === 'admin')
29
- * .then('email!')
30
- * .elseIf((data) => data.userType === 'vip')
31
- * .then('email')
32
- * .else(null)
33
- */
34
-
35
- class ConditionalBuilder {
36
- /**
37
- * 创建条件构建器实例
38
- * @private - 不直接调用,使用 dsl.if() 入口
39
- */
40
- constructor() {
41
- this._conditions = [];
42
- this._elseSchema = undefined;
43
- this._isConditional = true;
44
- }
45
-
46
- /**
47
- * 开始条件判断
48
- * @param {Function} conditionFn - 条件函数,接收完整数据对象
49
- * @returns {ConditionalBuilder} 当前实例(支持链式调用)
50
- *
51
- * @example
52
- * dsl.if((data) => data.age >= 18)
53
- */
54
- if(conditionFn) {
55
- if (typeof conditionFn !== 'function') {
56
- throw new Error('Condition must be a function');
57
- }
58
-
59
- this._conditions.push({
60
- type: 'if',
61
- condition: conditionFn,
62
- combinedConditions: [{ op: 'root', fn: conditionFn, message: null }]
63
- });
64
-
65
- return this;
66
- }
67
-
68
- /**
69
- * 添加 AND 条件(与前一个条件组合)
70
- * @param {Function} conditionFn - 条件函数
71
- * @returns {ConditionalBuilder} 当前实例(支持链式调用)
72
- *
73
- * @example
74
- * dsl.if((data) => data.age >= 18)
75
- * .and((data) => data.userType === 'admin')
76
- * .message('必须是管理员')
77
- * .then('email!')
78
- */
79
- and(conditionFn) {
80
- if (typeof conditionFn !== 'function') {
81
- throw new Error('Condition must be a function');
82
- }
83
-
84
- const last = this._conditions[this._conditions.length - 1];
85
- if (!last) {
86
- throw new Error('.and() must follow .if() or .elseIf()');
87
- }
88
-
89
- last.combinedConditions.push({ op: 'and', fn: conditionFn, message: null });
90
- return this;
91
- }
92
-
93
- /**
94
- * 添加 OR 条件(与前一个条件组合)
95
- * @param {Function} conditionFn - 条件函数
96
- * @returns {ConditionalBuilder} 当前实例(支持链式调用)
97
- *
98
- * @example
99
- * dsl.if((data) => data.age < 18)
100
- * .or((data) => data.isBlocked)
101
- * .message('不允许注册')
102
- */
103
- or(conditionFn) {
104
- if (typeof conditionFn !== 'function') {
105
- throw new Error('Condition must be a function');
106
- }
107
-
108
- const last = this._conditions[this._conditions.length - 1];
109
- if (!last) {
110
- throw new Error('.or() must follow .if() or .elseIf()');
111
- }
112
-
113
- last.combinedConditions.push({ op: 'or', fn: conditionFn, message: null });
114
- return this;
115
- }
116
-
117
- /**
118
- * 添加 else-if 分支
119
- * @param {Function} conditionFn - 条件函数
120
- * @returns {ConditionalBuilder} 当前实例(支持链式调用)
121
- *
122
- * @example
123
- * dsl.if((data) => data.userType === 'admin')
124
- * .then('email!')
125
- * .elseIf((data) => data.userType === 'vip')
126
- * .then('email')
127
- */
128
- elseIf(conditionFn) {
129
- if (typeof conditionFn !== 'function') {
130
- throw new Error('Condition must be a function');
131
- }
132
-
133
- if (this._conditions.length === 0) {
134
- throw new Error('.elseIf() must follow .if()');
135
- }
136
-
137
- this._conditions.push({
138
- type: 'elseIf',
139
- condition: conditionFn,
140
- combinedConditions: [{ op: 'root', fn: conditionFn, message: null }]
141
- });
142
-
143
- return this;
144
- }
145
-
146
- /**
147
- * 设置错误消息(支持多语言 key)
148
- * 条件为 true 时自动抛出此错误,条件为 false 时通过验证
149
- *
150
- * @param {string} msg - 错误消息或多语言 key
151
- * @returns {ConditionalBuilder} 当前实例(支持链式调用)
152
- *
153
- * @example
154
- * // 如果是未成年人,抛出错误
155
- * dsl.if((data) => data.age < 18)
156
- * .message('未成年用户不能注册')
157
- *
158
- * @example
159
- * // 为 and 条件设置独立消息
160
- * dsl.if((data) => !data)
161
- * .message('账户不存在')
162
- * .and((data) => data.balance < 100)
163
- * .message('余额不足')
164
- */
165
- message(msg) {
166
- if (typeof msg !== 'string') {
167
- throw new Error('Message must be a string');
168
- }
169
-
170
- const last = this._conditions[this._conditions.length - 1];
171
- if (!last) {
172
- throw new Error('.message() must follow .if() or .elseIf()');
173
- }
174
-
175
- // 找到最后一个添加的条件(可能是 root、and 或 or)
176
- const lastCombined = last.combinedConditions[last.combinedConditions.length - 1];
177
- if (lastCombined) {
178
- // 为最后一个组合条件设置消息
179
- lastCombined.message = msg;
180
- }
181
-
182
- // 同时设置整体消息(作为后备)
183
- last.message = msg;
184
- last.action = 'throw'; // 有 message 就自动 throw
185
- return this;
186
- }
187
-
188
- /**
189
- * 设置满足条件时的 Schema
190
- * @param {string|Object} schema - DSL 字符串或 Schema 对象
191
- * @returns {ConditionalBuilder} 当前实例(支持链式调用)
192
- *
193
- * @example
194
- * dsl.if((data) => data.userType === 'admin')
195
- * .then('email!')
196
- */
197
- then(schema) {
198
- const last = this._conditions[this._conditions.length - 1];
199
- if (!last) {
200
- throw new Error('.then() must follow .if() or .elseIf()');
201
- }
202
-
203
- last.then = schema;
204
- return this;
205
- }
206
-
207
- /**
208
- * 设置默认 Schema(所有条件都不满足时)
209
- * 可选:不写 else 就是不验证
210
- *
211
- * @param {string|Object|null} schema - DSL 字符串、Schema 对象或 null
212
- * @returns {ConditionalBuilder} 当前实例(支持链式调用)
213
- *
214
- * @example
215
- * // else 可选
216
- * dsl.if((data) => data.userType === 'admin')
217
- * .then('email!') // 不写 else
218
- *
219
- * @example
220
- * // 显式指定 else
221
- * dsl.if((data) => data.userType === 'admin')
222
- * .then('email!')
223
- * .else('email')
224
- */
225
- else(schema) {
226
- this._elseSchema = schema;
227
- return this;
228
- }
229
-
230
- /**
231
- * 执行组合条件(内部方法)
232
- * @private
233
- * @param {Object} conditionObj - 条件对象
234
- * @param {*} data - 待验证数据对象
235
- * @returns {Object} { result: boolean, failedMessage: string|null } 条件结果和失败消息
236
- *
237
- * 语义说明:
238
- * - 传统 AND 模式:所有条件都为 true 才失败
239
- * - 链式检查模式:root 有 message,且任何 .and() 也有独立 message 时
240
- * → 依次检查,第一个为 true 的失败
241
- */
242
- _evaluateCondition(conditionObj, data) {
243
- try {
244
- // 检查是否是链式检查模式:
245
- // 1. 必须是 message 模式(action='throw')
246
- // 2. root 条件有 message
247
- // 3. 有 .and() 条件(不管是否有独立 message)
248
- // 4. 没有 .or() 条件(有 OR 就使用传统逻辑)
249
- const isMessageMode = conditionObj.action === 'throw';
250
- const rootHasMessage = conditionObj.combinedConditions[0]?.message != null;
251
- const hasAndConditions = conditionObj.combinedConditions.some(c => c.op === 'and');
252
- const hasOrConditions = conditionObj.combinedConditions.some(c => c.op === 'or');
253
- const isChainCheckMode = isMessageMode && rootHasMessage && hasAndConditions && !hasOrConditions;
254
-
255
- let result = false;
256
- let failedMessage = null;
257
-
258
- for (let i = 0; i < conditionObj.combinedConditions.length; i++) {
259
- const combined = conditionObj.combinedConditions[i];
260
- let conditionResult = false;
261
-
262
- if (combined.op === 'root') {
263
- // 第一个条件
264
- conditionResult = combined.fn(data);
265
- result = conditionResult;
266
-
267
- if (isChainCheckMode) {
268
- // 链式检查模式:第一个条件为 true 就失败
269
- if (result) {
270
- failedMessage = combined.message || conditionObj.message;
271
- return { result: true, failedMessage };
272
- }
273
- } else {
274
- // 传统模式
275
- failedMessage = combined.message || conditionObj.message;
276
-
277
- // 如果第一个条件为 false,检查是否有 OR 条件
278
- if (!result) {
279
- const hasOrConditions = conditionObj.combinedConditions.some(c => c.op === 'or');
280
- if (!hasOrConditions) {
281
- // 没有 OR 条件,直接通过
282
- return { result: false, failedMessage: null };
283
- }
284
- // 有 OR 条件,继续检查
285
- }
286
- }
287
- } else if (combined.op === 'and') {
288
- conditionResult = combined.fn(data);
289
-
290
- if (isChainCheckMode) {
291
- // 链式检查模式:任一条件为 true 就失败
292
- if (conditionResult) {
293
- // 使用独立消息,如果没有则使用整体消息
294
- failedMessage = combined.message || conditionObj.message;
295
- return { result: true, failedMessage };
296
- }
297
- // 条件为 false,继续检查下一个条件
298
- } else {
299
- // 传统 AND 模式:所有条件都必须为 true 才失败
300
- if (!conditionResult) {
301
- // AND 条件为 false
302
- // 检查是否有 OR 条件
303
- if (hasOrConditions) {
304
- // 有 OR 条件,将 result 设为 false,继续检查 OR
305
- result = false;
306
- } else {
307
- // 没有 OR 条件,任一 AND 条件为 false 就验证通过
308
- return { result: false, failedMessage: null };
309
- }
310
- } else {
311
- // AND 条件为 true,继续累积
312
- result = true;
313
- }
314
- }
315
- } else if (combined.op === 'or') {
316
- // OR 逻辑:任一条件为 true 就失败
317
- if (!result) {
318
- conditionResult = combined.fn(data);
319
-
320
- if (conditionResult) {
321
- // OR 条件为 true
322
- result = true; // 更新 result
323
-
324
- if (isMessageMode) {
325
- // message 模式:立即返回失败
326
- failedMessage = combined.message || conditionObj.message;
327
- return { result: true, failedMessage };
328
- }
329
- // then/else 模式:继续累积 result(已经设置为true)
330
- }
331
- }
332
- }
333
- }
334
-
335
- // 返回最终结果
336
- if (isChainCheckMode) {
337
- // 链式检查模式:所有条件都为 false,验证通过
338
- return { result: false, failedMessage: null };
339
- } else {
340
- // 传统模式:返回累积结果
341
- return { result, failedMessage };
342
- }
343
- } catch (error) {
344
- // 条件函数执行出错,视为不满足
345
- return { result: false, failedMessage: null };
346
- }
347
- }
348
-
349
- /**
350
- * 转换为 Schema 对象(内部方法)
351
- * @private
352
- * @returns {Object} Schema 对象
353
- */
354
- toSchema() {
355
- return {
356
- _isConditional: true,
357
- conditions: this._conditions,
358
- else: this._elseSchema,
359
- // 保存 _evaluateCondition 方法供 Validator 使用
360
- _evaluateCondition: this._evaluateCondition.bind(this)
361
- };
362
- }
363
-
364
- /**
365
- * 快捷验证方法 - 返回完整验证结果
366
- * @param {*} data - 待验证的数据(任意类型)
367
- * @param {Object} options - 验证选项(可选)
368
- * @returns {Object} 验证结果 { valid, errors, data }
369
- *
370
- * @example
371
- * // 一行代码验证
372
- * const result = dsl.if(d => d.age < 18)
373
- * .message('未成年')
374
- * .validate({ age: 16 });
375
- *
376
- * @example
377
- * // 复用验证器
378
- * const validator = dsl.if(d => d.age < 18).message('未成年');
379
- * const r1 = validator.validate({ age: 16 });
380
- * const r2 = validator.validate({ age: 20 });
381
- *
382
- * @example
383
- * // 非对象类型
384
- * const result = dsl.if(d => d.includes('@'))
385
- * .then('email!')
386
- * .validate('test@example.com');
387
- */
388
- validate(data, options = {}) {
389
- const Validator = require('./Validator');
390
- const validator = new Validator(options);
391
- return validator.validate(this.toSchema(), data, options);
392
- }
393
-
394
- /**
395
- * 异步验证方法 - 失败自动抛出异常
396
- * @param {*} data - 待验证的数据
397
- * @param {Object} options - 验证选项(可选)
398
- * @returns {Promise<*>} 验证通过返回数据,失败抛出异常
399
- * @throws {ValidationError} 验证失败抛出异常
400
- *
401
- * @example
402
- * // 异步验证,失败自动抛错
403
- * try {
404
- * const data = await dsl.if(d => d.age < 18)
405
- * .message('未成年')
406
- * .validateAsync({ age: 16 });
407
- * } catch (error) {
408
- * console.log(error.message); // "未成年"
409
- * }
410
- *
411
- * @example
412
- * // Express 中间件
413
- * app.post('/register', async (req, res, next) => {
414
- * try {
415
- * await dsl.if(d => d.age < 18)
416
- * .message('未成年用户不能注册')
417
- * .validateAsync(req.body);
418
- * // 验证通过,继续处理...
419
- * } catch (error) {
420
- * next(error);
421
- * }
422
- * });
423
- */
424
- async validateAsync(data, options = {}) {
425
- const Validator = require('./Validator');
426
- const validator = new Validator(options);
427
- return validator.validateAsync(this.toSchema(), data, options);
428
- }
429
-
430
- /**
431
- * 断言方法 - 同步验证,失败直接抛错
432
- * @param {*} data - 待验证的数据
433
- * @param {Object} options - 验证选项(可选)
434
- * @returns {*} 验证通过返回数据
435
- * @throws {Error} 验证失败抛出错误
436
- *
437
- * @example
438
- * // 断言验证,失败直接抛错
439
- * try {
440
- * dsl.if(d => d.age < 18)
441
- * .message('未成年')
442
- * .assert({ age: 16 });
443
- * } catch (error) {
444
- * console.log(error.message); // "未成年"
445
- * }
446
- *
447
- * @example
448
- * // 函数中快速断言
449
- * function registerUser(userData) {
450
- * dsl.if(d => d.age < 18)
451
- * .message('未成年用户不能注册')
452
- * .assert(userData);
453
- *
454
- * // 验证通过,继续处理...
455
- * return createUser(userData);
456
- * }
457
- */
458
- assert(data, options = {}) {
459
- const result = this.validate(data, options);
460
- if (!result.valid) {
461
- const error = new Error(result.errors[0].message);
462
- error.errors = result.errors;
463
- error.name = 'ValidationError';
464
- throw error;
465
- }
466
- return data;
467
- }
468
-
469
- /**
470
- * 快捷检查方法 - 只返回 boolean
471
- * @param {*} data - 待验证的数据
472
- * @returns {boolean} 验证是否通过
473
- *
474
- * @example
475
- * // 快速判断
476
- * const isValid = dsl.if(d => d.age < 18)
477
- * .message('未成年')
478
- * .check({ age: 16 });
479
- * // => false
480
- *
481
- * @example
482
- * // 断言场景
483
- * if (!validator.check(userData)) {
484
- * console.log('验证失败');
485
- * }
486
- */
487
- check(data) {
488
- return this.validate(data).valid;
489
- }
490
-
491
- /**
492
- * 静态工厂方法 - dsl.if() 入口
493
- * @static
494
- * @param {Function} conditionFn - 条件函数
495
- * @returns {ConditionalBuilder} 新的构建器实例
496
- */
497
- static start(conditionFn) {
498
- return new ConditionalBuilder().if(conditionFn);
499
- }
500
- }
501
-
502
- module.exports = ConditionalBuilder;
503
-