schema-dsl 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -1249,6 +1249,86 @@ declare module 'schema-dsl' {
1249
1249
  *
1250
1250
  * JavaScript 用户请直接使用 `dsl.if()`
1251
1251
  * TypeScript 用户可以使用 `dsl['if']()` 或 `dsl._if()`
1252
+ *
1253
+ * @alias _if
1254
+ */
1255
+ export const _if: (condition: any, thenSchema: any, elseSchema?: any) => any;
1256
+
1257
+ /**
1258
+ * 多语言错误快捷方法 (v1.1.1+)
1259
+ *
1260
+ * @description 统一的多语言错误抛出机制
1261
+ *
1262
+ * @example
1263
+ * ```typescript
1264
+ * import { dsl } from 'schema-dsl';
1265
+ *
1266
+ * // 创建错误
1267
+ * const error = dsl.error.create('account.notFound');
1268
+ *
1269
+ * // 直接抛出
1270
+ * dsl.error.throw('account.notFound');
1271
+ *
1272
+ * // 断言风格
1273
+ * dsl.error.assert(account, 'account.notFound');
1274
+ * dsl.error.assert(
1275
+ * account.balance >= 100,
1276
+ * 'account.insufficientBalance',
1277
+ * { balance: account.balance, required: 100 }
1278
+ * );
1279
+ * ```
1280
+ */
1281
+ export const error: {
1282
+ /**
1283
+ * 创建多语言错误(不抛出)
1284
+ * @param code - 错误代码(多语言 key)
1285
+ * @param params - 错误参数
1286
+ * @param statusCode - HTTP 状态码
1287
+ * @returns 错误实例
1288
+ */
1289
+ create(
1290
+ code: string,
1291
+ params?: Record<string, any>,
1292
+ statusCode?: number
1293
+ ): I18nError;
1294
+
1295
+ /**
1296
+ * 抛出多语言错误
1297
+ * @param code - 错误代码(多语言 key)
1298
+ * @param params - 错误参数
1299
+ * @param statusCode - HTTP 状态码
1300
+ * @throws I18nError
1301
+ */
1302
+ throw(
1303
+ code: string,
1304
+ params?: Record<string, any>,
1305
+ statusCode?: number
1306
+ ): never;
1307
+
1308
+ /**
1309
+ * 断言方法 - 条件不满足时抛错
1310
+ * @param condition - 条件表达式
1311
+ * @param code - 错误代码(多语言 key)
1312
+ * @param params - 错误参数
1313
+ * @param statusCode - HTTP 状态码
1314
+ * @throws I18nError 条件为 false 时抛出
1315
+ */
1316
+ assert(
1317
+ condition: any,
1318
+ code: string,
1319
+ params?: Record<string, any>,
1320
+ statusCode?: number
1321
+ ): asserts condition;
1322
+ };
1323
+ }
1324
+
1325
+ /**
1326
+ * 条件规则的别名(用于 TypeScript)
1327
+ *
1328
+ * @description 因为 TypeScript 中 `if` 是保留字,提供 `_if` 作为别名
1329
+ *
1330
+ * JavaScript 用户请直接使用 `dsl.if()`
1331
+ * TypeScript 用户可以使用 `dsl['if']()` 或 `dsl._if()`
1252
1332
  */
1253
1333
  export { _if as if };
1254
1334
 
@@ -1572,6 +1652,161 @@ declare module 'schema-dsl' {
1572
1652
  getErrorCount(): number;
1573
1653
  }
1574
1654
 
1655
+ /**
1656
+ * I18nError - 多语言错误类
1657
+ *
1658
+ * @version 1.1.1
1659
+ *
1660
+ * @description 统一的多语言错误抛出机制,支持:
1661
+ * - 多语言 key 自动翻译
1662
+ * - 参数插值(如 {{#balance}}, {{#required}})
1663
+ * - 自定义错误代码
1664
+ * - Express/Koa 集成
1665
+ *
1666
+ * @example 基础用法
1667
+ * ```typescript
1668
+ * import { I18nError } from 'schema-dsl';
1669
+ *
1670
+ * // 直接抛出
1671
+ * throw I18nError.create('account.notFound');
1672
+ * // 中文: "账户不存在"
1673
+ * // 英文: "Account not found"
1674
+ * ```
1675
+ *
1676
+ * @example 带参数
1677
+ * ```typescript
1678
+ * I18nError.throw('account.insufficientBalance', {
1679
+ * balance: 50,
1680
+ * required: 100
1681
+ * });
1682
+ * // 输出: "余额不足,当前余额50,需要100"
1683
+ * ```
1684
+ *
1685
+ * @example 断言风格
1686
+ * ```typescript
1687
+ * function getAccount(id: string) {
1688
+ * const account = db.findAccount(id);
1689
+ * I18nError.assert(account, 'account.notFound');
1690
+ * I18nError.assert(
1691
+ * account.balance >= 100,
1692
+ * 'account.insufficientBalance',
1693
+ * { balance: account.balance, required: 100 }
1694
+ * );
1695
+ * return account;
1696
+ * }
1697
+ * ```
1698
+ *
1699
+ * @example Express 集成
1700
+ * ```typescript
1701
+ * app.use((error, req, res, next) => {
1702
+ * if (error instanceof I18nError) {
1703
+ * return res.status(error.statusCode).json(error.toJSON());
1704
+ * }
1705
+ * next(error);
1706
+ * });
1707
+ * ```
1708
+ */
1709
+ export class I18nError extends Error {
1710
+ /** 错误名称(固定为 'I18nError') */
1711
+ readonly name: 'I18nError';
1712
+
1713
+ /** 错误消息(已翻译) */
1714
+ message: string;
1715
+
1716
+ /** 错误代码(多语言 key) */
1717
+ code: string;
1718
+
1719
+ /** 错误参数(用于插值) */
1720
+ params: Record<string, any>;
1721
+
1722
+ /** HTTP 状态码 */
1723
+ statusCode: number;
1724
+
1725
+ /** 使用的语言环境 */
1726
+ locale: string;
1727
+
1728
+ /**
1729
+ * 构造函数
1730
+ * @param code - 错误代码(多语言 key)
1731
+ * @param params - 错误参数(用于插值)
1732
+ * @param statusCode - HTTP 状态码(默认 400)
1733
+ * @param locale - 语言环境(默认使用当前语言)
1734
+ */
1735
+ constructor(
1736
+ code: string,
1737
+ params?: Record<string, any>,
1738
+ statusCode?: number,
1739
+ locale?: string
1740
+ );
1741
+
1742
+ /**
1743
+ * 静态工厂方法 - 创建错误(不抛出)
1744
+ * @param code - 错误代码
1745
+ * @param params - 错误参数
1746
+ * @param statusCode - HTTP 状态码
1747
+ * @returns 错误实例
1748
+ */
1749
+ static create(
1750
+ code: string,
1751
+ params?: Record<string, any>,
1752
+ statusCode?: number
1753
+ ): I18nError;
1754
+
1755
+ /**
1756
+ * 静态工厂方法 - 直接抛出错误
1757
+ * @param code - 错误代码
1758
+ * @param params - 错误参数
1759
+ * @param statusCode - HTTP 状态码
1760
+ * @throws I18nError
1761
+ */
1762
+ static throw(
1763
+ code: string,
1764
+ params?: Record<string, any>,
1765
+ statusCode?: number
1766
+ ): never;
1767
+
1768
+ /**
1769
+ * 断言方法 - 条件不满足时抛错
1770
+ * @param condition - 条件表达式
1771
+ * @param code - 错误代码
1772
+ * @param params - 错误参数
1773
+ * @param statusCode - HTTP 状态码
1774
+ * @throws I18nError 条件为 false 时抛出
1775
+ */
1776
+ static assert(
1777
+ condition: any,
1778
+ code: string,
1779
+ params?: Record<string, any>,
1780
+ statusCode?: number
1781
+ ): asserts condition;
1782
+
1783
+ /**
1784
+ * 检查错误是否为指定代码
1785
+ * @param code - 错误代码
1786
+ * @returns 是否匹配
1787
+ */
1788
+ is(code: string): boolean;
1789
+
1790
+ /**
1791
+ * 转为 JSON 格式(用于 API 响应)
1792
+ * @returns JSON 对象
1793
+ */
1794
+ toJSON(): {
1795
+ error: string;
1796
+ code: string;
1797
+ message: string;
1798
+ params: Record<string, any>;
1799
+ statusCode: number;
1800
+ locale: string;
1801
+ };
1802
+
1803
+ /**
1804
+ * 转为字符串
1805
+ * @returns 格式化的错误信息
1806
+ */
1807
+ toString(): string;
1808
+ }
1809
+
1575
1810
  /**
1576
1811
  * 获取默认Validator实例(单例)
1577
1812
  *
@@ -2893,15 +3128,74 @@ declare module 'schema-dsl' {
2893
3128
 
2894
3129
  /**
2895
3130
  * 添加 AND 条件(与前一个条件组合)
3131
+ *
3132
+ * @version 1.1.1 支持为每个 .and() 条件设置独立的错误消息
3133
+ *
2896
3134
  * @param condition - 条件函数
2897
3135
  * @returns 当前实例(支持链式调用)
3136
+ *
3137
+ * @example 基础用法(传统 AND 逻辑)
3138
+ * ```typescript
3139
+ * // 所有条件都为 true 才失败
3140
+ * dsl.if(d => d.age >= 18)
3141
+ * .and(d => d.userType === 'admin')
3142
+ * .then('email!')
3143
+ * ```
3144
+ *
3145
+ * @example v1.1.0+ 独立消息(推荐)
3146
+ * ```typescript
3147
+ * // 每个条件都有自己的错误消息
3148
+ * dsl.if(d => !d)
3149
+ * .message('ACCOUNT_NOT_FOUND')
3150
+ * .and(d => d.balance < 100)
3151
+ * .message('INSUFFICIENT_BALANCE')
3152
+ * .assert(account);
3153
+ *
3154
+ * // 工作原理:链式检查模式
3155
+ * // - 第一个条件失败 → 返回 'ACCOUNT_NOT_FOUND'
3156
+ * // - 第二个条件失败 → 返回 'INSUFFICIENT_BALANCE'
3157
+ * // - 所有条件通过 → 验证成功
3158
+ * ```
3159
+ *
3160
+ * @example 多个 .and() 条件
3161
+ * ```typescript
3162
+ * dsl.if(d => !d)
3163
+ * .message('NOT_FOUND')
3164
+ * .and(d => d.status !== 'active')
3165
+ * .message('INACTIVE')
3166
+ * .and(d => d.balance < 100)
3167
+ * .message('INSUFFICIENT')
3168
+ * .assert(account);
3169
+ * // 依次检查,第一个失败的返回其消息
3170
+ * ```
2898
3171
  */
2899
3172
  and(condition: (data: any) => boolean): this;
2900
3173
 
2901
3174
  /**
2902
3175
  * 添加 OR 条件(与前一个条件组合)
3176
+ *
3177
+ * @version 1.1.1 支持为 .or() 条件设置独立的错误消息
3178
+ *
2903
3179
  * @param condition - 条件函数
2904
3180
  * @returns 当前实例(支持链式调用)
3181
+ *
3182
+ * @example 基础用法
3183
+ * ```typescript
3184
+ * // 任一条件为 true 就失败
3185
+ * dsl.if((data) => data.age < 18)
3186
+ * .or((data) => data.isBlocked)
3187
+ * .message('不允许注册')
3188
+ * ```
3189
+ *
3190
+ * @example v1.1.0+ 独立消息
3191
+ * ```typescript
3192
+ * dsl.if(d => d.age < 18)
3193
+ * .message('未成年用户不能注册')
3194
+ * .or(d => d.isBlocked)
3195
+ * .message('账户已被封禁')
3196
+ * .assert(data);
3197
+ * // 哪个条件为 true 就返回哪个消息
3198
+ * ```
2905
3199
  */
2906
3200
  or(condition: (data: any) => boolean): this;
2907
3201
 
@@ -2914,16 +3208,45 @@ declare module 'schema-dsl' {
2914
3208
 
2915
3209
  /**
2916
3210
  * 设置错误消息(支持多语言 key)
3211
+ *
3212
+ * @version 1.1.1 支持为 .and() 和 .or() 条件设置独立消息
3213
+ *
2917
3214
  * 条件为 true 时自动抛出此错误
3215
+ *
2918
3216
  * @param msg - 错误消息或多语言 key
2919
3217
  * @returns 当前实例(支持链式调用)
2920
3218
  *
2921
- * @example
3219
+ * @example 基础用法
2922
3220
  * ```typescript
2923
3221
  * // 如果是未成年人(条件为true),抛出错误
2924
3222
  * dsl.if((data) => data.age < 18)
2925
3223
  * .message('未成年用户不能注册')
2926
3224
  * ```
3225
+ *
3226
+ * @example v1.1.0+ 为 .and() 设置独立消息
3227
+ * ```typescript
3228
+ * dsl.if((data) => !data)
3229
+ * .message('账户不存在')
3230
+ * .and((data) => data.balance < 100)
3231
+ * .message('余额不足')
3232
+ * .assert(account);
3233
+ * // 每个条件都有自己的错误消息
3234
+ * ```
3235
+ *
3236
+ * @example 链式检查模式说明
3237
+ * ```typescript
3238
+ * // 启用条件:
3239
+ * // 1. 使用 .message() 模式(不是 .then()/.else())
3240
+ * // 2. root 条件有 .message()
3241
+ * // 3. 有 .and() 条件
3242
+ * // 4. 没有 .or() 条件
3243
+ *
3244
+ * // ✅ 启用链式检查
3245
+ * dsl.if(d => !d).message('A').and(d => d < 100).message('B')
3246
+ *
3247
+ * // ❌ 不启用(有 .or())
3248
+ * dsl.if(d => !d).message('A').and(d => d < 100).or(d => d > 200).message('B')
3249
+ * ```
2927
3250
  */
2928
3251
  message(msg: string): this;
2929
3252
 
package/index.js CHANGED
@@ -22,6 +22,10 @@ const ErrorCodes = require('./lib/core/ErrorCodes');
22
22
  const MessageTemplate = require('./lib/core/MessageTemplate');
23
23
  const Locale = require('./lib/core/Locale');
24
24
 
25
+ // ========== 错误类 ==========
26
+ const ValidationError = require('./lib/errors/ValidationError');
27
+ const I18nError = require('./lib/errors/I18nError');
28
+
25
29
  // ========== String 扩展 ==========
26
30
  const { installStringExtensions, uninstallStringExtensions } = require('./lib/core/StringExtensions');
27
31
 
@@ -48,6 +52,36 @@ dsl.if = function(...args) {
48
52
  return ConditionalBuilder.start(args[0]);
49
53
  };
50
54
 
55
+ // ✅ dsl.error:统一的多语言错误抛出(v1.1.1+)
56
+ dsl.error = {
57
+ /**
58
+ * 创建多语言错误(不抛出)
59
+ * @param {string} code - 错误代码(多语言 key)
60
+ * @param {Object} params - 错误参数
61
+ * @param {number} statusCode - HTTP 状态码
62
+ * @returns {I18nError} 错误实例
63
+ */
64
+ create: (code, params, statusCode) => I18nError.create(code, params, statusCode),
65
+
66
+ /**
67
+ * 抛出多语言错误
68
+ * @param {string} code - 错误代码(多语言 key)
69
+ * @param {Object} params - 错误参数
70
+ * @param {number} statusCode - HTTP 状态码
71
+ * @throws {I18nError} 直接抛出错误
72
+ */
73
+ throw: (code, params, statusCode) => I18nError.throw(code, params, statusCode),
74
+
75
+ /**
76
+ * 断言方法 - 条件不满足时抛错
77
+ * @param {boolean} condition - 条件表达式
78
+ * @param {string} code - 错误代码(多语言 key)
79
+ * @param {Object} params - 错误参数
80
+ * @param {number} statusCode - HTTP 状态码
81
+ */
82
+ assert: (condition, code, params, statusCode) => I18nError.assert(condition, code, params, statusCode)
83
+ };
84
+
51
85
  /**
52
86
  * 全局配置
53
87
  * @param {Object} options - 配置选项
@@ -182,8 +216,6 @@ installStringExtensions(dsl);
182
216
 
183
217
  // ========== 导出 ==========
184
218
 
185
- // 导入 ValidationError
186
- const ValidationError = require('./lib/errors/ValidationError');
187
219
 
188
220
  // 导入 validateAsync
189
221
  const { validateAsync } = require('./lib/adapters/DslAdapter');
@@ -214,6 +246,7 @@ module.exports = {
214
246
 
215
247
  // 错误类 (v2.1.0 新增)
216
248
  ValidationError,
249
+ I18nError, // v1.1.1 新增:多语言错误类
217
250
 
218
251
  // 错误消息系统
219
252
  ErrorCodes,
@@ -59,7 +59,7 @@ class ConditionalBuilder {
59
59
  this._conditions.push({
60
60
  type: 'if',
61
61
  condition: conditionFn,
62
- combinedConditions: [{ op: 'root', fn: conditionFn }]
62
+ combinedConditions: [{ op: 'root', fn: conditionFn, message: null }]
63
63
  });
64
64
 
65
65
  return this;
@@ -73,6 +73,7 @@ class ConditionalBuilder {
73
73
  * @example
74
74
  * dsl.if((data) => data.age >= 18)
75
75
  * .and((data) => data.userType === 'admin')
76
+ * .message('必须是管理员')
76
77
  * .then('email!')
77
78
  */
78
79
  and(conditionFn) {
@@ -85,7 +86,7 @@ class ConditionalBuilder {
85
86
  throw new Error('.and() must follow .if() or .elseIf()');
86
87
  }
87
88
 
88
- last.combinedConditions.push({ op: 'and', fn: conditionFn });
89
+ last.combinedConditions.push({ op: 'and', fn: conditionFn, message: null });
89
90
  return this;
90
91
  }
91
92
 
@@ -109,7 +110,7 @@ class ConditionalBuilder {
109
110
  throw new Error('.or() must follow .if() or .elseIf()');
110
111
  }
111
112
 
112
- last.combinedConditions.push({ op: 'or', fn: conditionFn });
113
+ last.combinedConditions.push({ op: 'or', fn: conditionFn, message: null });
113
114
  return this;
114
115
  }
115
116
 
@@ -136,7 +137,7 @@ class ConditionalBuilder {
136
137
  this._conditions.push({
137
138
  type: 'elseIf',
138
139
  condition: conditionFn,
139
- combinedConditions: [{ op: 'root', fn: conditionFn }]
140
+ combinedConditions: [{ op: 'root', fn: conditionFn, message: null }]
140
141
  });
141
142
 
142
143
  return this;
@@ -144,7 +145,7 @@ class ConditionalBuilder {
144
145
 
145
146
  /**
146
147
  * 设置错误消息(支持多语言 key)
147
- t * 条件为 true 时自动抛出此错误,条件为 false 时通过验证
148
+ * 条件为 true 时自动抛出此错误,条件为 false 时通过验证
148
149
  *
149
150
  * @param {string} msg - 错误消息或多语言 key
150
151
  * @returns {ConditionalBuilder} 当前实例(支持链式调用)
@@ -153,6 +154,13 @@ t * 条件为 true 时自动抛出此错误,条件为 false 时通过验证
153
154
  * // 如果是未成年人,抛出错误
154
155
  * dsl.if((data) => data.age < 18)
155
156
  * .message('未成年用户不能注册')
157
+ *
158
+ * @example
159
+ * // 为 and 条件设置独立消息
160
+ * dsl.if((data) => !data)
161
+ * .message('账户不存在')
162
+ * .and((data) => data.balance < 100)
163
+ * .message('余额不足')
156
164
  */
157
165
  message(msg) {
158
166
  if (typeof msg !== 'string') {
@@ -164,6 +172,14 @@ t * 条件为 true 时自动抛出此错误,条件为 false 时通过验证
164
172
  throw new Error('.message() must follow .if() or .elseIf()');
165
173
  }
166
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
+ // 同时设置整体消息(作为后备)
167
183
  last.message = msg;
168
184
  last.action = 'throw'; // 有 message 就自动 throw
169
185
  return this;
@@ -216,31 +232,117 @@ t * 条件为 true 时自动抛出此错误,条件为 false 时通过验证
216
232
  * @private
217
233
  * @param {Object} conditionObj - 条件对象
218
234
  * @param {*} data - 待验证数据对象
219
- * @returns {boolean} 条件结果
235
+ * @returns {Object} { result: boolean, failedMessage: string|null } 条件结果和失败消息
236
+ *
237
+ * 语义说明:
238
+ * - 传统 AND 模式:所有条件都为 true 才失败
239
+ * - 链式检查模式:root 有 message,且任何 .and() 也有独立 message 时
240
+ * → 依次检查,第一个为 true 的失败
220
241
  */
221
242
  _evaluateCondition(conditionObj, data) {
222
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
+
223
255
  let result = false;
256
+ let failedMessage = null;
224
257
 
225
258
  for (let i = 0; i < conditionObj.combinedConditions.length; i++) {
226
259
  const combined = conditionObj.combinedConditions[i];
260
+ let conditionResult = false;
227
261
 
228
262
  if (combined.op === 'root') {
229
263
  // 第一个条件
230
- result = combined.fn(data);
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
+ }
231
287
  } else if (combined.op === 'and') {
232
- // AND 组合
233
- result = result && combined.fn(data);
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
+ }
234
315
  } else if (combined.op === 'or') {
235
- // OR 组合
236
- result = result || combined.fn(data);
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
+ }
237
332
  }
238
333
  }
239
334
 
240
- return result;
335
+ // 返回最终结果
336
+ if (isChainCheckMode) {
337
+ // 链式检查模式:所有条件都为 false,验证通过
338
+ return { result: false, failedMessage: null };
339
+ } else {
340
+ // 传统模式:返回累积结果
341
+ return { result, failedMessage };
342
+ }
241
343
  } catch (error) {
242
344
  // 条件函数执行出错,视为不满足
243
- return false;
345
+ return { result: false, failedMessage: null };
244
346
  }
245
347
  }
246
348
 
@@ -464,16 +464,20 @@ class Validator {
464
464
  for (let i = 0; i < conditionalSchema.conditions.length; i++) {
465
465
  const cond = conditionalSchema.conditions[i];
466
466
 
467
- // 执行组合条件(支持 and/or
468
- const matched = conditionalSchema._evaluateCondition(cond, data);
467
+ // 执行组合条件(支持 and/or),获取结果和失败消息
468
+ const evaluation = conditionalSchema._evaluateCondition(cond, data);
469
+ const matched = evaluation.result;
470
+ const failedMessage = evaluation.failedMessage;
469
471
 
470
472
  if (cond.action === 'throw') {
471
473
  // ✅ message 模式:条件为 true 时抛错,条件为 false 时通过
472
474
  if (matched) {
473
475
  // ✅ 条件满足(true),抛出错误
476
+ // 优先使用具体的失败消息,如果没有则使用整体消息
477
+ const errorMsg = failedMessage || cond.message;
474
478
  // 支持多语言:如果 message 是 key(如 'conditional.underAge'),从语言包获取翻译
475
479
  // 传递 locale 参数以支持动态语言切换
476
- const errorMessage = Locale.getMessage(cond.message, options.messages || {}, locale);
480
+ const errorMessage = Locale.getMessage(errorMsg, options.messages || {}, locale);
477
481
 
478
482
  return {
479
483
  valid: false,