schema-dsl 1.0.8 → 1.1.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.
- package/CHANGELOG.md +338 -3
- package/README.md +296 -17
- package/STATUS.md +74 -3
- package/docs/FEATURE-INDEX.md +1 -1
- package/docs/add-custom-locale.md +395 -0
- package/docs/best-practices.md +3 -3
- package/docs/cache-manager.md +1 -1
- package/docs/conditional-api.md +1032 -0
- package/docs/dsl-syntax.md +1 -1
- package/docs/dynamic-locale.md +76 -30
- package/docs/error-handling.md +2 -2
- package/docs/export-guide.md +2 -2
- package/docs/export-limitations.md +3 -3
- package/docs/faq.md +6 -6
- package/docs/frontend-i18n-guide.md +19 -16
- package/docs/i18n-user-guide.md +7 -9
- package/docs/i18n.md +65 -2
- package/docs/mongodb-exporter.md +3 -3
- package/docs/multi-type-support.md +12 -2
- package/docs/mysql-exporter.md +1 -1
- package/docs/plugin-system.md +4 -4
- package/docs/postgresql-exporter.md +1 -1
- package/docs/quick-start.md +4 -4
- package/docs/troubleshooting.md +2 -2
- package/docs/type-reference.md +5 -5
- package/docs/typescript-guide.md +5 -6
- package/docs/union-type-guide.md +147 -0
- package/docs/union-types.md +277 -0
- package/docs/validate-async.md +1 -1
- package/examples/array-dsl-example.js +1 -1
- package/examples/conditional-example.js +288 -0
- package/examples/conditional-non-object.js +129 -0
- package/examples/conditional-validate-example.js +321 -0
- package/examples/union-type-example.js +127 -0
- package/examples/union-types-example.js +77 -0
- package/index.d.ts +395 -12
- package/index.js +31 -4
- package/lib/adapters/DslAdapter.js +14 -5
- package/lib/core/ConditionalBuilder.js +401 -0
- package/lib/core/DslBuilder.js +113 -0
- package/lib/core/ErrorFormatter.js +81 -33
- package/lib/core/Locale.js +13 -8
- package/lib/core/Validator.js +252 -16
- package/lib/locales/en-US.js +14 -0
- package/lib/locales/es-ES.js +4 -0
- package/lib/locales/fr-FR.js +4 -0
- package/lib/locales/ja-JP.js +9 -0
- package/lib/locales/zh-CN.js +14 -0
- package/package.json +5 -2
package/index.d.ts
CHANGED
|
@@ -112,6 +112,35 @@ declare module 'schema-dsl' {
|
|
|
112
112
|
field?: string;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
/**
|
|
116
|
+
* 验证选项
|
|
117
|
+
*
|
|
118
|
+
* @description validate() 和 Validator.validate() 的配置选项
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* const options: ValidateOptions = {
|
|
123
|
+
* format: true,
|
|
124
|
+
* locale: 'zh-CN',
|
|
125
|
+
* messages: {
|
|
126
|
+
* min: '至少需要 {{#limit}} 个字符'
|
|
127
|
+
* }
|
|
128
|
+
* };
|
|
129
|
+
*
|
|
130
|
+
* const result = validate(schema, data, options);
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
export interface ValidateOptions {
|
|
134
|
+
/** 是否格式化错误(默认true) */
|
|
135
|
+
format?: boolean;
|
|
136
|
+
/** 动态指定语言(如 'zh-CN', 'en-US', 'ja-JP', 'es-ES', 'fr-FR') */
|
|
137
|
+
locale?: string;
|
|
138
|
+
/** 自定义错误消息 */
|
|
139
|
+
messages?: ErrorMessages;
|
|
140
|
+
/** 扩展选项 */
|
|
141
|
+
[key: string]: any;
|
|
142
|
+
}
|
|
143
|
+
|
|
115
144
|
/**
|
|
116
145
|
* 错误消息对象
|
|
117
146
|
*
|
|
@@ -189,14 +218,82 @@ declare module 'schema-dsl' {
|
|
|
189
218
|
* ```
|
|
190
219
|
*/
|
|
191
220
|
export class DslBuilder {
|
|
221
|
+
/**
|
|
222
|
+
* 注册自定义类型(供插件使用)
|
|
223
|
+
* @param name - 类型名称
|
|
224
|
+
* @param schema - JSON Schema对象或生成函数
|
|
225
|
+
* @static
|
|
226
|
+
* @since v1.1.0
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* ```typescript
|
|
230
|
+
* // 注册自定义类型
|
|
231
|
+
* DslBuilder.registerType('phone-cn', {
|
|
232
|
+
* type: 'string',
|
|
233
|
+
* pattern: '^1[3-9]\\d{9}$',
|
|
234
|
+
* minLength: 11,
|
|
235
|
+
* maxLength: 11
|
|
236
|
+
* });
|
|
237
|
+
*
|
|
238
|
+
* // 在DSL中使用
|
|
239
|
+
* const schema = dsl({ phone: 'phone-cn!' });
|
|
240
|
+
* const schema2 = dsl({ contact: 'types:email|phone-cn' });
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
243
|
+
static registerType(name: string, schema: JSONSchema | (() => JSONSchema)): void;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* 检查类型是否已注册
|
|
247
|
+
* @param type - 类型名称
|
|
248
|
+
* @returns 是否已注册
|
|
249
|
+
* @static
|
|
250
|
+
* @since v1.1.0
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```typescript
|
|
254
|
+
* DslBuilder.hasType('string'); // true (内置)
|
|
255
|
+
* DslBuilder.hasType('phone-cn'); // false (未注册)
|
|
256
|
+
* DslBuilder.registerType('phone-cn', { ... });
|
|
257
|
+
* DslBuilder.hasType('phone-cn'); // true (已注册)
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
static hasType(type: string): boolean;
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* 获取所有已注册的自定义类型
|
|
264
|
+
* @returns 自定义类型名称数组
|
|
265
|
+
* @static
|
|
266
|
+
* @since v1.1.0
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```typescript
|
|
270
|
+
* const types = DslBuilder.getCustomTypes();
|
|
271
|
+
* console.log(types); // ['phone-cn', 'order-id', ...]
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
274
|
+
static getCustomTypes(): string[];
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* 清除所有自定义类型(主要用于测试)
|
|
278
|
+
* @static
|
|
279
|
+
* @since v1.1.0
|
|
280
|
+
*
|
|
281
|
+
* @example
|
|
282
|
+
* ```typescript
|
|
283
|
+
* DslBuilder.clearCustomTypes();
|
|
284
|
+
* ```
|
|
285
|
+
*/
|
|
286
|
+
static clearCustomTypes(): void;
|
|
287
|
+
|
|
192
288
|
/**
|
|
193
289
|
* 构造函数
|
|
194
|
-
* @param dslString - DSL字符串(如 'email!', 'string:3-32!')
|
|
195
|
-
*
|
|
290
|
+
* @param dslString - DSL字符串(如 'email!', 'string:3-32!', 'types:string|number')
|
|
291
|
+
*
|
|
196
292
|
* @example
|
|
197
293
|
* ```typescript
|
|
198
294
|
* const builder = new DslBuilder('email!');
|
|
199
295
|
* const builder2 = new DslBuilder('string:3-32');
|
|
296
|
+
* const builder3 = new DslBuilder('types:string|number');
|
|
200
297
|
* ```
|
|
201
298
|
*/
|
|
202
299
|
constructor(dslString: string);
|
|
@@ -302,11 +399,8 @@ declare module 'schema-dsl' {
|
|
|
302
399
|
* });
|
|
303
400
|
* ```
|
|
304
401
|
*/
|
|
305
|
-
when(
|
|
306
|
-
|
|
307
|
-
then: DslBuilder | JSONSchema;
|
|
308
|
-
otherwise?: DslBuilder | JSONSchema;
|
|
309
|
-
}): this;
|
|
402
|
+
// ⚠️ DEPRECATED: .when() method removed - use dsl.if() instead
|
|
403
|
+
// when(refField: string, options: { is: any; then: DslBuilder | JSONSchema; otherwise?: DslBuilder | JSONSchema; }): this;
|
|
310
404
|
|
|
311
405
|
/**
|
|
312
406
|
* 设置默认值
|
|
@@ -1257,9 +1351,27 @@ declare module 'schema-dsl' {
|
|
|
1257
1351
|
* 验证数据
|
|
1258
1352
|
* @param schema - JSON Schema对象
|
|
1259
1353
|
* @param data - 要验证的数据
|
|
1354
|
+
* @param options - 验证选项
|
|
1260
1355
|
* @returns 验证结果
|
|
1356
|
+
*
|
|
1357
|
+
* @example
|
|
1358
|
+
* ```typescript
|
|
1359
|
+
* const validator = new Validator();
|
|
1360
|
+
*
|
|
1361
|
+
* // 使用默认语言
|
|
1362
|
+
* const result1 = validator.validate(schema, data);
|
|
1363
|
+
*
|
|
1364
|
+
* // 动态指定语言
|
|
1365
|
+
* const result2 = validator.validate(schema, data, { locale: 'zh-CN' });
|
|
1366
|
+
*
|
|
1367
|
+
* // 自定义错误消息
|
|
1368
|
+
* const result3 = validator.validate(schema, data, {
|
|
1369
|
+
* locale: 'zh-CN',
|
|
1370
|
+
* messages: { min: '至少{{#limit}}个字符' }
|
|
1371
|
+
* });
|
|
1372
|
+
* ```
|
|
1261
1373
|
*/
|
|
1262
|
-
validate<T = any>(schema: JSONSchema, data: any): ValidationResult<T>;
|
|
1374
|
+
validate<T = any>(schema: JSONSchema, data: any, options?: ValidateOptions): ValidationResult<T>;
|
|
1263
1375
|
|
|
1264
1376
|
/**
|
|
1265
1377
|
* 获取底层ajv实例
|
|
@@ -1300,14 +1412,25 @@ declare module 'schema-dsl' {
|
|
|
1300
1412
|
* import { dsl, validate } from 'schema-dsl';
|
|
1301
1413
|
*
|
|
1302
1414
|
* const schema = dsl({ email: 'email!' });
|
|
1303
|
-
*
|
|
1304
|
-
*
|
|
1305
|
-
*
|
|
1415
|
+
*
|
|
1416
|
+
* // 基本验证
|
|
1417
|
+
* const result1 = validate(schema, { email: 'test@example.com' });
|
|
1418
|
+
*
|
|
1419
|
+
* // 指定语言
|
|
1420
|
+
* const result2 = validate(schema, { email: 'invalid' }, { locale: 'zh-CN' });
|
|
1421
|
+
*
|
|
1422
|
+
* if (result2.valid) {
|
|
1306
1423
|
* console.log('验证通过');
|
|
1424
|
+
* } else {
|
|
1425
|
+
* console.log('错误:', result2.errors); // 中文错误消息
|
|
1307
1426
|
* }
|
|
1308
1427
|
* ```
|
|
1309
1428
|
*/
|
|
1310
|
-
export function validate<T = any>(
|
|
1429
|
+
export function validate<T = any>(
|
|
1430
|
+
schema: JSONSchema | SchemaIO,
|
|
1431
|
+
data: any,
|
|
1432
|
+
options?: ValidateOptions
|
|
1433
|
+
): ValidationResult<T>;
|
|
1311
1434
|
|
|
1312
1435
|
/**
|
|
1313
1436
|
* 便捷异步验证方法(推荐)
|
|
@@ -2730,6 +2853,266 @@ declare module 'schema-dsl' {
|
|
|
2730
2853
|
*/
|
|
2731
2854
|
export const VERSION: string;
|
|
2732
2855
|
|
|
2856
|
+
/**
|
|
2857
|
+
* 链式条件构建器
|
|
2858
|
+
*
|
|
2859
|
+
* @description 提供流畅的条件判断 API,类似 JavaScript if-else 语句
|
|
2860
|
+
*
|
|
2861
|
+
* @example
|
|
2862
|
+
* ```typescript
|
|
2863
|
+
* import { dsl } from 'schema-dsl';
|
|
2864
|
+
*
|
|
2865
|
+
* // 简单条件 + 错误消息
|
|
2866
|
+
* const schema = dsl({
|
|
2867
|
+
* email: dsl.if((data) => data.age >= 18)
|
|
2868
|
+
* .message('未成年用户不能注册')
|
|
2869
|
+
* });
|
|
2870
|
+
*
|
|
2871
|
+
* // 多条件 and
|
|
2872
|
+
* const schema2 = dsl({
|
|
2873
|
+
* email: dsl.if((data) => data.age >= 18)
|
|
2874
|
+
* .and((data) => data.userType === 'admin')
|
|
2875
|
+
* .then('email!')
|
|
2876
|
+
* });
|
|
2877
|
+
*
|
|
2878
|
+
* // 多条件 or
|
|
2879
|
+
* const schema3 = dsl({
|
|
2880
|
+
* status: dsl.if((data) => data.age < 18)
|
|
2881
|
+
* .or((data) => data.isBlocked)
|
|
2882
|
+
* .message('不允许注册')
|
|
2883
|
+
* });
|
|
2884
|
+
* ```
|
|
2885
|
+
*/
|
|
2886
|
+
export class ConditionalBuilder {
|
|
2887
|
+
/**
|
|
2888
|
+
* 开始条件判断
|
|
2889
|
+
* @param condition - 条件函数,接收完整数据对象
|
|
2890
|
+
* @returns 当前实例(支持链式调用)
|
|
2891
|
+
*/
|
|
2892
|
+
if(condition: (data: any) => boolean): this;
|
|
2893
|
+
|
|
2894
|
+
/**
|
|
2895
|
+
* 添加 AND 条件(与前一个条件组合)
|
|
2896
|
+
* @param condition - 条件函数
|
|
2897
|
+
* @returns 当前实例(支持链式调用)
|
|
2898
|
+
*/
|
|
2899
|
+
and(condition: (data: any) => boolean): this;
|
|
2900
|
+
|
|
2901
|
+
/**
|
|
2902
|
+
* 添加 OR 条件(与前一个条件组合)
|
|
2903
|
+
* @param condition - 条件函数
|
|
2904
|
+
* @returns 当前实例(支持链式调用)
|
|
2905
|
+
*/
|
|
2906
|
+
or(condition: (data: any) => boolean): this;
|
|
2907
|
+
|
|
2908
|
+
/**
|
|
2909
|
+
* 添加 else-if 分支
|
|
2910
|
+
* @param condition - 条件函数
|
|
2911
|
+
* @returns 当前实例(支持链式调用)
|
|
2912
|
+
*/
|
|
2913
|
+
elseIf(condition: (data: any) => boolean): this;
|
|
2914
|
+
|
|
2915
|
+
/**
|
|
2916
|
+
* 设置错误消息(支持多语言 key)
|
|
2917
|
+
* 条件为 true 时自动抛出此错误
|
|
2918
|
+
* @param msg - 错误消息或多语言 key
|
|
2919
|
+
* @returns 当前实例(支持链式调用)
|
|
2920
|
+
*
|
|
2921
|
+
* @example
|
|
2922
|
+
* ```typescript
|
|
2923
|
+
* // 如果是未成年人(条件为true),抛出错误
|
|
2924
|
+
* dsl.if((data) => data.age < 18)
|
|
2925
|
+
* .message('未成年用户不能注册')
|
|
2926
|
+
* ```
|
|
2927
|
+
*/
|
|
2928
|
+
message(msg: string): this;
|
|
2929
|
+
|
|
2930
|
+
/**
|
|
2931
|
+
* 设置满足条件时的 Schema
|
|
2932
|
+
* @param schema - DSL 字符串或 Schema 对象
|
|
2933
|
+
* @returns 当前实例(支持链式调用)
|
|
2934
|
+
*/
|
|
2935
|
+
then(schema: string | DslBuilder | JSONSchema): this;
|
|
2936
|
+
|
|
2937
|
+
/**
|
|
2938
|
+
* 设置默认 Schema(所有条件都不满足时)
|
|
2939
|
+
* 可选:不写 else 就是不验证
|
|
2940
|
+
* @param schema - DSL 字符串、Schema 对象或 null
|
|
2941
|
+
* @returns 当前实例(支持链式调用)
|
|
2942
|
+
*/
|
|
2943
|
+
else(schema: string | DslBuilder | JSONSchema | null): this;
|
|
2944
|
+
|
|
2945
|
+
/**
|
|
2946
|
+
* 快捷验证方法 - 返回完整验证结果
|
|
2947
|
+
* @param data - 待验证的数据(任意类型)
|
|
2948
|
+
* @param options - 验证选项(可选)
|
|
2949
|
+
* @returns 验证结果 { valid, errors, data }
|
|
2950
|
+
*
|
|
2951
|
+
* @example
|
|
2952
|
+
* ```typescript
|
|
2953
|
+
* // 一行代码验证
|
|
2954
|
+
* const result = dsl.if(d => d.age < 18)
|
|
2955
|
+
* .message('未成年')
|
|
2956
|
+
* .validate({ age: 16 });
|
|
2957
|
+
*
|
|
2958
|
+
* // 复用验证器
|
|
2959
|
+
* const validator = dsl.if(d => d.age < 18).message('未成年');
|
|
2960
|
+
* const r1 = validator.validate({ age: 16 });
|
|
2961
|
+
* const r2 = validator.validate({ age: 20 });
|
|
2962
|
+
* ```
|
|
2963
|
+
*/
|
|
2964
|
+
validate<T = any>(data: T, options?: ValidateOptions): ValidationResult<T>;
|
|
2965
|
+
|
|
2966
|
+
/**
|
|
2967
|
+
* 异步验证方法 - 失败自动抛出异常
|
|
2968
|
+
* @param data - 待验证的数据
|
|
2969
|
+
* @param options - 验证选项(可选)
|
|
2970
|
+
* @returns 验证通过返回数据,失败抛出异常
|
|
2971
|
+
* @throws ValidationError 验证失败抛出异常
|
|
2972
|
+
*
|
|
2973
|
+
* @example
|
|
2974
|
+
* ```typescript
|
|
2975
|
+
* // 异步验证,失败自动抛错
|
|
2976
|
+
* try {
|
|
2977
|
+
* const data = await dsl.if(d => d.age < 18)
|
|
2978
|
+
* .message('未成年')
|
|
2979
|
+
* .validateAsync({ age: 16 });
|
|
2980
|
+
* } catch (error) {
|
|
2981
|
+
* console.log(error.message);
|
|
2982
|
+
* }
|
|
2983
|
+
*
|
|
2984
|
+
* // Express 中间件
|
|
2985
|
+
* app.post('/register', async (req, res, next) => {
|
|
2986
|
+
* try {
|
|
2987
|
+
* await dsl.if(d => d.age < 18)
|
|
2988
|
+
* .message('未成年用户不能注册')
|
|
2989
|
+
* .validateAsync(req.body);
|
|
2990
|
+
* // 验证通过,继续处理...
|
|
2991
|
+
* } catch (error) {
|
|
2992
|
+
* next(error);
|
|
2993
|
+
* }
|
|
2994
|
+
* });
|
|
2995
|
+
* ```
|
|
2996
|
+
*/
|
|
2997
|
+
validateAsync<T = any>(data: T, options?: ValidateOptions): Promise<T>;
|
|
2998
|
+
|
|
2999
|
+
/**
|
|
3000
|
+
* 断言方法 - 同步验证,失败直接抛错
|
|
3001
|
+
* @param data - 待验证的数据
|
|
3002
|
+
* @param options - 验证选项(可选)
|
|
3003
|
+
* @returns 验证通过返回数据
|
|
3004
|
+
* @throws Error 验证失败抛出错误
|
|
3005
|
+
*
|
|
3006
|
+
* @example
|
|
3007
|
+
* ```typescript
|
|
3008
|
+
* // 断言验证,失败直接抛错
|
|
3009
|
+
* try {
|
|
3010
|
+
* dsl.if(d => d.age < 18)
|
|
3011
|
+
* .message('未成年')
|
|
3012
|
+
* .assert({ age: 16 });
|
|
3013
|
+
* } catch (error) {
|
|
3014
|
+
* console.log(error.message);
|
|
3015
|
+
* }
|
|
3016
|
+
*
|
|
3017
|
+
* // 函数中快速断言
|
|
3018
|
+
* function registerUser(userData: any) {
|
|
3019
|
+
* dsl.if(d => d.age < 18)
|
|
3020
|
+
* .message('未成年用户不能注册')
|
|
3021
|
+
* .assert(userData);
|
|
3022
|
+
*
|
|
3023
|
+
* // 验证通过,继续处理...
|
|
3024
|
+
* return createUser(userData);
|
|
3025
|
+
* }
|
|
3026
|
+
* ```
|
|
3027
|
+
*/
|
|
3028
|
+
assert<T = any>(data: T, options?: ValidateOptions): T;
|
|
3029
|
+
|
|
3030
|
+
/**
|
|
3031
|
+
* 快捷检查方法 - 只返回 boolean
|
|
3032
|
+
* @param data - 待验证的数据
|
|
3033
|
+
* @returns 验证是否通过
|
|
3034
|
+
*
|
|
3035
|
+
* @example
|
|
3036
|
+
* ```typescript
|
|
3037
|
+
* // 快速判断
|
|
3038
|
+
* const isValid = dsl.if(d => d.age < 18)
|
|
3039
|
+
* .message('未成年')
|
|
3040
|
+
* .check({ age: 16 });
|
|
3041
|
+
* // => false
|
|
3042
|
+
*
|
|
3043
|
+
* // 断言场景
|
|
3044
|
+
* if (!validator.check(userData)) {
|
|
3045
|
+
* console.log('验证失败');
|
|
3046
|
+
* }
|
|
3047
|
+
* ```
|
|
3048
|
+
*/
|
|
3049
|
+
check(data: any): boolean;
|
|
3050
|
+
}
|
|
3051
|
+
|
|
3052
|
+
/**
|
|
3053
|
+
* dsl 函数扩展:条件判断(支持两种方式)
|
|
3054
|
+
*/
|
|
3055
|
+
export interface DslFunction {
|
|
3056
|
+
/**
|
|
3057
|
+
* 方式一:函数条件(运行时动态判断)
|
|
3058
|
+
*
|
|
3059
|
+
* 创建链式条件构建器,在验证时根据实际数据动态判断
|
|
3060
|
+
*
|
|
3061
|
+
* @param condition - 条件函数,接收完整数据对象
|
|
3062
|
+
* @returns ConditionalBuilder 实例
|
|
3063
|
+
*
|
|
3064
|
+
* @example 简单条件 + 错误消息
|
|
3065
|
+
* ```typescript
|
|
3066
|
+
* const schema = dsl({
|
|
3067
|
+
* age: 'number!',
|
|
3068
|
+
* status: dsl.if((data) => data.age < 18)
|
|
3069
|
+
* .message('未成年用户不能注册')
|
|
3070
|
+
* });
|
|
3071
|
+
* ```
|
|
3072
|
+
*
|
|
3073
|
+
* @example 条件 + then/else(动态Schema)
|
|
3074
|
+
* ```typescript
|
|
3075
|
+
* const schema = dsl({
|
|
3076
|
+
* userType: 'string!',
|
|
3077
|
+
* email: dsl.if((data) => data.userType === 'admin')
|
|
3078
|
+
* .then('email!') // 管理员必填
|
|
3079
|
+
* .else('email') // 普通用户可选
|
|
3080
|
+
* });
|
|
3081
|
+
* ```
|
|
3082
|
+
*
|
|
3083
|
+
* @example 多条件组合
|
|
3084
|
+
* ```typescript
|
|
3085
|
+
* const schema = dsl({
|
|
3086
|
+
* email: dsl.if((data) => data.age >= 18)
|
|
3087
|
+
* .and((data) => data.userType === 'admin')
|
|
3088
|
+
* .then('email!')
|
|
3089
|
+
* .else('email')
|
|
3090
|
+
* });
|
|
3091
|
+
* ```
|
|
3092
|
+
*/
|
|
3093
|
+
if(condition: (data: any) => boolean): ConditionalBuilder;
|
|
3094
|
+
|
|
3095
|
+
/**
|
|
3096
|
+
* 方式二:字段条件(Schema 定义时静态判断)
|
|
3097
|
+
*
|
|
3098
|
+
* 基于字段值的静态布尔条件判断
|
|
3099
|
+
*
|
|
3100
|
+
* @param conditionField - 条件字段名
|
|
3101
|
+
* @param thenSchema - 条件为 true 时的 Schema
|
|
3102
|
+
* @param elseSchema - 条件为 false 时的 Schema
|
|
3103
|
+
* @returns 条件结构对象
|
|
3104
|
+
*
|
|
3105
|
+
* @example 基于字段值的条件
|
|
3106
|
+
* ```typescript
|
|
3107
|
+
* const schema = dsl({
|
|
3108
|
+
* isVip: 'boolean',
|
|
3109
|
+
* discount: dsl.if('isVip', 'number:0-50', 'number:0-10')
|
|
3110
|
+
* });
|
|
3111
|
+
* ```
|
|
3112
|
+
*/
|
|
3113
|
+
if(conditionField: string, thenSchema: string | DslBuilder | JSONSchema, elseSchema?: string | DslBuilder | JSONSchema): any;
|
|
3114
|
+
}
|
|
3115
|
+
|
|
2733
3116
|
/**
|
|
2734
3117
|
* 默认导出(dsl函数)
|
|
2735
3118
|
*
|
package/index.js
CHANGED
|
@@ -15,6 +15,7 @@ const ErrorFormatter = require('./lib/core/ErrorFormatter');
|
|
|
15
15
|
const CacheManager = require('./lib/core/CacheManager');
|
|
16
16
|
const DslBuilder = require('./lib/core/DslBuilder');
|
|
17
17
|
const PluginManager = require('./lib/core/PluginManager');
|
|
18
|
+
const ConditionalBuilder = require('./lib/core/ConditionalBuilder');
|
|
18
19
|
|
|
19
20
|
// ========== 错误消息系统 ==========
|
|
20
21
|
const ErrorCodes = require('./lib/core/ErrorCodes');
|
|
@@ -29,7 +30,23 @@ const dsl = require('./lib/adapters/DslAdapter');
|
|
|
29
30
|
|
|
30
31
|
// 挂载静态方法 (v2.1.0)
|
|
31
32
|
dsl.match = dsl.DslAdapter.match;
|
|
32
|
-
|
|
33
|
+
|
|
34
|
+
// ✅ 智能 dsl.if:根据参数类型选择实现
|
|
35
|
+
dsl.if = function(...args) {
|
|
36
|
+
// 如果第一个参数是函数 → 使用新的 ConditionalBuilder(链式API)
|
|
37
|
+
if (typeof args[0] === 'function') {
|
|
38
|
+
return ConditionalBuilder.start(args[0]);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 如果第一个参数是字符串且有3个参数 → 使用原有的字段条件实现
|
|
42
|
+
// dsl.if('fieldName', thenSchema, elseSchema)
|
|
43
|
+
if (typeof args[0] === 'string' && args.length >= 2) {
|
|
44
|
+
return dsl.DslAdapter.if(args[0], args[1], args[2]);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 其他情况 → 调用 ConditionalBuilder 让它抛出正确的错误
|
|
48
|
+
return ConditionalBuilder.start(args[0]);
|
|
49
|
+
};
|
|
33
50
|
|
|
34
51
|
/**
|
|
35
52
|
* 全局配置
|
|
@@ -128,16 +145,25 @@ function getDefaultValidator() {
|
|
|
128
145
|
* 便捷验证方法(使用默认Validator)
|
|
129
146
|
* @param {Object} schema - JSON Schema对象
|
|
130
147
|
* @param {*} data - 待验证数据
|
|
148
|
+
* @param {Object} [options] - 验证选项
|
|
149
|
+
* @param {boolean} [options.format=true] - 是否格式化错误
|
|
150
|
+
* @param {string} [options.locale] - 动态指定语言(如 'zh-CN', 'en-US')
|
|
151
|
+
* @param {Object} [options.messages] - 自定义错误消息
|
|
131
152
|
* @returns {Object} 验证结果
|
|
132
153
|
*
|
|
133
154
|
* @example
|
|
134
155
|
* const { validate, dsl } = require('schema-dsl');
|
|
135
156
|
*
|
|
136
157
|
* const schema = dsl({ email: 'email!' });
|
|
137
|
-
*
|
|
158
|
+
*
|
|
159
|
+
* // 基本验证
|
|
160
|
+
* const result1 = validate(schema, { email: 'test@example.com' });
|
|
161
|
+
*
|
|
162
|
+
* // 指定语言
|
|
163
|
+
* const result2 = validate(schema, { email: 'invalid' }, { locale: 'zh-CN' });
|
|
138
164
|
*/
|
|
139
|
-
function validate(schema, data) {
|
|
140
|
-
return getDefaultValidator().validate(schema, data);
|
|
165
|
+
function validate(schema, data, options) {
|
|
166
|
+
return getDefaultValidator().validate(schema, data, options);
|
|
141
167
|
}
|
|
142
168
|
|
|
143
169
|
// ========== 工具函数 ==========
|
|
@@ -177,6 +203,7 @@ module.exports = {
|
|
|
177
203
|
// 核心类
|
|
178
204
|
JSONSchemaCore,
|
|
179
205
|
Validator,
|
|
206
|
+
DslBuilder, // v1.1.0 新增:导出DslBuilder供插件使用
|
|
180
207
|
|
|
181
208
|
// 便捷方法(推荐)
|
|
182
209
|
validate, // 便捷验证(单例)
|
|
@@ -349,7 +349,7 @@ class DslAdapter {
|
|
|
349
349
|
// 占位Schema,确保字段存在
|
|
350
350
|
fieldSchema = { description: `Depends on ${value.field}` };
|
|
351
351
|
}
|
|
352
|
-
// 2. If 结构 (dsl.if)
|
|
352
|
+
// 2. If 结构 (dsl.if - 旧版本)
|
|
353
353
|
else if (value && value._isIf) {
|
|
354
354
|
const ifSchema = this._buildIfSchema(value.condition, fieldKey, value.then, value.else);
|
|
355
355
|
if (ifSchema) {
|
|
@@ -358,20 +358,29 @@ class DslAdapter {
|
|
|
358
358
|
}
|
|
359
359
|
fieldSchema = { description: `Conditional field based on ${value.condition}` };
|
|
360
360
|
}
|
|
361
|
-
// 3.
|
|
361
|
+
// 3. ConditionalBuilder 结构 (dsl.if - 新版本)
|
|
362
|
+
else if (value && value._isConditional) {
|
|
363
|
+
// 调用 toSchema() 转换为 Schema 对象
|
|
364
|
+
const conditionalSchema = typeof value.toSchema === 'function'
|
|
365
|
+
? value.toSchema()
|
|
366
|
+
: value;
|
|
367
|
+
// 保存条件链,留待 Validator 执行
|
|
368
|
+
fieldSchema = conditionalSchema;
|
|
369
|
+
}
|
|
370
|
+
// 4. DslBuilder 实例(链式调用结果)
|
|
362
371
|
else if (value instanceof DslBuilder) {
|
|
363
372
|
fieldSchema = value.toSchema();
|
|
364
373
|
}
|
|
365
|
-
//
|
|
374
|
+
// 5. 纯字符串 DSL
|
|
366
375
|
else if (typeof value === 'string') {
|
|
367
376
|
const builder = new DslBuilder(value);
|
|
368
377
|
fieldSchema = builder.toSchema();
|
|
369
378
|
}
|
|
370
|
-
//
|
|
379
|
+
// 6. 嵌套对象
|
|
371
380
|
else if (typeof value === 'object' && !Array.isArray(value) && value !== null) {
|
|
372
381
|
fieldSchema = this.parseObject(value);
|
|
373
382
|
}
|
|
374
|
-
//
|
|
383
|
+
// 7. 其他类型(保留原样)
|
|
375
384
|
else {
|
|
376
385
|
fieldSchema = value;
|
|
377
386
|
}
|