schema-dsl 1.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.
- package/.eslintignore +10 -0
- package/.eslintrc.json +27 -0
- package/.github/CODE_OF_CONDUCT.md +45 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +57 -0
- package/.github/ISSUE_TEMPLATE/config.yml +11 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +45 -0
- package/.github/ISSUE_TEMPLATE/question.md +31 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +70 -0
- package/.github/SECURITY.md +184 -0
- package/.github/workflows/ci.yml +33 -0
- package/CHANGELOG.md +633 -0
- package/CONTRIBUTING.md +368 -0
- package/LICENSE +21 -0
- package/README.md +1184 -0
- package/STATUS.md +101 -0
- package/docs/FEATURE-INDEX.md +519 -0
- package/docs/INDEX.md +253 -0
- package/docs/api-reference.md +1096 -0
- package/docs/best-practices.md +672 -0
- package/docs/cache-manager.md +336 -0
- package/docs/design-philosophy.md +601 -0
- package/docs/dsl-syntax.md +653 -0
- package/docs/dynamic-locale.md +552 -0
- package/docs/error-handling.md +703 -0
- package/docs/export-guide.md +462 -0
- package/docs/export-limitations.md +551 -0
- package/docs/faq.md +577 -0
- package/docs/frontend-i18n-guide.md +290 -0
- package/docs/i18n-user-guide.md +476 -0
- package/docs/label-vs-description.md +262 -0
- package/docs/markdown-exporter.md +397 -0
- package/docs/mongodb-exporter.md +295 -0
- package/docs/multi-type-support.md +319 -0
- package/docs/mysql-exporter.md +273 -0
- package/docs/plugin-system.md +542 -0
- package/docs/postgresql-exporter.md +304 -0
- package/docs/quick-start.md +761 -0
- package/docs/schema-helper.md +340 -0
- package/docs/schema-utils-chaining.md +143 -0
- package/docs/schema-utils.md +490 -0
- package/docs/string-extensions.md +480 -0
- package/docs/troubleshooting.md +471 -0
- package/docs/type-converter.md +319 -0
- package/docs/type-reference.md +219 -0
- package/docs/validate-async.md +480 -0
- package/docs/validate.md +486 -0
- package/docs/validation-guide.md +484 -0
- package/examples/array-dsl-example.js +227 -0
- package/examples/custom-extension.js +85 -0
- package/examples/dsl-match-example.js +74 -0
- package/examples/dsl-style.js +118 -0
- package/examples/dynamic-locale-configuration.js +348 -0
- package/examples/dynamic-locale-example.js +287 -0
- package/examples/export-demo.js +130 -0
- package/examples/express-integration.js +376 -0
- package/examples/i18n-full-demo.js +310 -0
- package/examples/i18n-memory-safety.examples.js +268 -0
- package/examples/markdown-export.js +71 -0
- package/examples/middleware-usage.js +93 -0
- package/examples/new-features-comparison.js +315 -0
- package/examples/password-reset/README.md +153 -0
- package/examples/password-reset/schema.js +26 -0
- package/examples/password-reset/test.js +101 -0
- package/examples/plugin-system.examples.js +205 -0
- package/examples/schema-utils-chaining.examples.js +250 -0
- package/examples/simple-example.js +122 -0
- package/examples/string-extensions.js +297 -0
- package/examples/user-registration/README.md +156 -0
- package/examples/user-registration/routes.js +92 -0
- package/examples/user-registration/schema.js +150 -0
- package/examples/user-registration/server.js +74 -0
- package/index.d.ts +1999 -0
- package/index.js +282 -0
- package/index.mjs +30 -0
- package/lib/adapters/DslAdapter.js +699 -0
- package/lib/adapters/index.js +20 -0
- package/lib/config/constants.js +286 -0
- package/lib/config/patterns/creditCard.js +9 -0
- package/lib/config/patterns/idCard.js +9 -0
- package/lib/config/patterns/index.js +8 -0
- package/lib/config/patterns/licensePlate.js +4 -0
- package/lib/config/patterns/passport.js +4 -0
- package/lib/config/patterns/phone.js +9 -0
- package/lib/config/patterns/postalCode.js +5 -0
- package/lib/core/CacheManager.js +376 -0
- package/lib/core/DslBuilder.js +740 -0
- package/lib/core/ErrorCodes.js +233 -0
- package/lib/core/ErrorFormatter.js +342 -0
- package/lib/core/JSONSchemaCore.js +347 -0
- package/lib/core/Locale.js +119 -0
- package/lib/core/MessageTemplate.js +89 -0
- package/lib/core/PluginManager.js +448 -0
- package/lib/core/StringExtensions.js +209 -0
- package/lib/core/Validator.js +376 -0
- package/lib/errors/ValidationError.js +191 -0
- package/lib/exporters/MarkdownExporter.js +420 -0
- package/lib/exporters/MongoDBExporter.js +162 -0
- package/lib/exporters/MySQLExporter.js +212 -0
- package/lib/exporters/PostgreSQLExporter.js +289 -0
- package/lib/exporters/index.js +24 -0
- package/lib/locales/en-US.js +65 -0
- package/lib/locales/es-ES.js +66 -0
- package/lib/locales/fr-FR.js +66 -0
- package/lib/locales/index.js +8 -0
- package/lib/locales/ja-JP.js +66 -0
- package/lib/locales/zh-CN.js +93 -0
- package/lib/utils/LRUCache.js +174 -0
- package/lib/utils/SchemaHelper.js +240 -0
- package/lib/utils/SchemaUtils.js +445 -0
- package/lib/utils/TypeConverter.js +245 -0
- package/lib/utils/index.js +13 -0
- package/lib/validators/CustomKeywords.js +203 -0
- package/lib/validators/index.js +11 -0
- package/package.json +70 -0
- package/plugins/custom-format.js +101 -0
- package/plugins/custom-validator.js +200 -0
package/index.d.ts
ADDED
|
@@ -0,0 +1,1999 @@
|
|
|
1
|
+
// Type definitions for SchemaIO v2.1.2
|
|
2
|
+
// Project: https://github.com/schema-dsl/schema-dsl
|
|
3
|
+
// Definitions by: SchemaIO Team
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
declare module 'schema-dsl' {
|
|
7
|
+
// ========== 核心类型 ==========
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* JSON Schema 对象
|
|
11
|
+
*
|
|
12
|
+
* @description JSON Schema draft-07 规范的类型定义
|
|
13
|
+
* @see https://json-schema.org/draft-07/schema
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const schema: JSONSchema = {
|
|
18
|
+
* type: 'object',
|
|
19
|
+
* properties: {
|
|
20
|
+
* username: { type: 'string', minLength: 3, maxLength: 32 },
|
|
21
|
+
* email: { type: 'string', format: 'email' }
|
|
22
|
+
* },
|
|
23
|
+
* required: ['username', 'email']
|
|
24
|
+
* };
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export interface JSONSchema {
|
|
28
|
+
/** 数据类型 */
|
|
29
|
+
type?: string | string[];
|
|
30
|
+
/** 对象属性定义 */
|
|
31
|
+
properties?: Record<string, JSONSchema>;
|
|
32
|
+
/** 必填字段列表 */
|
|
33
|
+
required?: string[];
|
|
34
|
+
/** 字符串/数组最小长度 */
|
|
35
|
+
minLength?: number;
|
|
36
|
+
/** 字符串/数组最大长度 */
|
|
37
|
+
maxLength?: number;
|
|
38
|
+
/** 数字最小值 */
|
|
39
|
+
minimum?: number;
|
|
40
|
+
/** 数字最大值 */
|
|
41
|
+
maximum?: number;
|
|
42
|
+
/** 正则表达式验证 */
|
|
43
|
+
pattern?: string;
|
|
44
|
+
/** 格式验证(email, url, date等) */
|
|
45
|
+
format?: string;
|
|
46
|
+
/** 枚举值 */
|
|
47
|
+
enum?: any[];
|
|
48
|
+
/** 数组项定义 */
|
|
49
|
+
items?: JSONSchema;
|
|
50
|
+
/** 字段标题 */
|
|
51
|
+
title?: string;
|
|
52
|
+
/** 字段描述 */
|
|
53
|
+
description?: string;
|
|
54
|
+
/** 默认值 */
|
|
55
|
+
default?: any;
|
|
56
|
+
/** 示例值 */
|
|
57
|
+
examples?: any[];
|
|
58
|
+
/** 扩展字段 */
|
|
59
|
+
[key: string]: any;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 验证结果
|
|
64
|
+
*
|
|
65
|
+
* @description validate()方法的返回值类型
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* const result: ValidationResult = schema.validate({ username: 'test' });
|
|
70
|
+
*
|
|
71
|
+
* if (result.valid) {
|
|
72
|
+
* console.log('验证通过', result.data);
|
|
73
|
+
* } else {
|
|
74
|
+
* console.log('验证失败', result.errors);
|
|
75
|
+
* }
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export interface ValidationResult<T = any> {
|
|
79
|
+
/** 是否验证通过 */
|
|
80
|
+
valid: boolean;
|
|
81
|
+
/** 验证错误列表(仅在valid=false时存在) */
|
|
82
|
+
errors?: ValidationError[];
|
|
83
|
+
/** 验证后的数据(仅在valid=true时存在) */
|
|
84
|
+
data?: T;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* 验证错误
|
|
89
|
+
*
|
|
90
|
+
* @description 详细的验证错误信息
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```typescript
|
|
94
|
+
* const error: ValidationError = {
|
|
95
|
+
* message: '用户名至少需要 3 个字符',
|
|
96
|
+
* path: 'username',
|
|
97
|
+
* keyword: 'minLength',
|
|
98
|
+
* params: { limit: 3 }
|
|
99
|
+
* };
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export interface ValidationError {
|
|
103
|
+
/** 错误消息 */
|
|
104
|
+
message: string;
|
|
105
|
+
/** 错误字段路径(使用点号分隔) */
|
|
106
|
+
path: string;
|
|
107
|
+
/** 验证关键字(min, max, email等) */
|
|
108
|
+
keyword: string;
|
|
109
|
+
/** 验证参数 */
|
|
110
|
+
params?: Record<string, any>;
|
|
111
|
+
/** 错误字段(别名,同path) */
|
|
112
|
+
field?: string;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* 错误消息对象
|
|
117
|
+
*
|
|
118
|
+
* @description 自定义错误消息的配置对象
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* const messages: ErrorMessages = {
|
|
123
|
+
* min: '至少需要 {{#limit}} 个字符',
|
|
124
|
+
* max: '最多 {{#limit}} 个字符',
|
|
125
|
+
* email: '邮箱格式不正确',
|
|
126
|
+
* required: '这是必填项'
|
|
127
|
+
* };
|
|
128
|
+
*
|
|
129
|
+
* const schema = dsl({ email: 'email!' }, { messages });
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
export interface ErrorMessages {
|
|
133
|
+
/** 最小长度/最小值错误 (v2.1.2+: 推荐使用min代替minLength) */
|
|
134
|
+
min?: string;
|
|
135
|
+
/** 最大长度/最大值错误 (v2.1.2+: 推荐使用max代替maxLength) */
|
|
136
|
+
max?: string;
|
|
137
|
+
/** 最小长度错误 (向后兼容,推荐使用min) */
|
|
138
|
+
minLength?: string;
|
|
139
|
+
/** 最大长度错误 (向后兼容,推荐使用max) */
|
|
140
|
+
maxLength?: string;
|
|
141
|
+
/** 最小值错误 (向后兼容,推荐使用min) */
|
|
142
|
+
minimum?: string;
|
|
143
|
+
/** 最大值错误 (向后兼容,推荐使用max) */
|
|
144
|
+
maximum?: string;
|
|
145
|
+
/** 数组最小长度错误 (向后兼容,推荐使用min) */
|
|
146
|
+
minItems?: string;
|
|
147
|
+
/** 数组最大长度错误 (向后兼容,推荐使用max) */
|
|
148
|
+
maxItems?: string;
|
|
149
|
+
/** 正则表达式验证错误 */
|
|
150
|
+
pattern?: string;
|
|
151
|
+
/** 格式验证错误 */
|
|
152
|
+
format?: string;
|
|
153
|
+
/** 枚举值验证错误 */
|
|
154
|
+
enum?: string;
|
|
155
|
+
/** 邮箱格式错误 */
|
|
156
|
+
email?: string;
|
|
157
|
+
/** URL格式错误 */
|
|
158
|
+
url?: string;
|
|
159
|
+
/** 必填项错误 */
|
|
160
|
+
required?: string;
|
|
161
|
+
/** 类型错误 */
|
|
162
|
+
type?: string;
|
|
163
|
+
/** 自定义错误消息 */
|
|
164
|
+
[key: string]: string | undefined;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ========== DslBuilder 类 ==========
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* DSL Builder 类
|
|
171
|
+
*
|
|
172
|
+
* @description 提供链式API来构建Schema定义
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* // 基础用法
|
|
177
|
+
* const builder = new DslBuilder('email!');
|
|
178
|
+
* builder.pattern(/custom/).label('邮箱地址');
|
|
179
|
+
*
|
|
180
|
+
* // 链式调用
|
|
181
|
+
* const schema = new DslBuilder('string:3-32!')
|
|
182
|
+
* .pattern(/^[a-zA-Z0-9_]+$/, '只能包含字母、数字和下划线')
|
|
183
|
+
* .label('用户名')
|
|
184
|
+
* .messages({
|
|
185
|
+
* min: '至少3个字符',
|
|
186
|
+
* max: '最多32个字符'
|
|
187
|
+
* })
|
|
188
|
+
* .toSchema();
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
export class DslBuilder {
|
|
192
|
+
/**
|
|
193
|
+
* 构造函数
|
|
194
|
+
* @param dslString - DSL字符串(如 'email!', 'string:3-32!')
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```typescript
|
|
198
|
+
* const builder = new DslBuilder('email!');
|
|
199
|
+
* const builder2 = new DslBuilder('string:3-32');
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
constructor(dslString: string);
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* 添加正则验证
|
|
206
|
+
* @param regex - 正则表达式或字符串
|
|
207
|
+
* @param message - 自定义错误消息
|
|
208
|
+
* @returns 当前实例(支持链式调用)
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```typescript
|
|
212
|
+
* builder
|
|
213
|
+
* .pattern(/^[a-zA-Z]+$/)
|
|
214
|
+
* .pattern('^\\d{6}$', '必须是6位数字');
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
pattern(regex: RegExp | string, message?: string): this;
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* 设置字段标签
|
|
221
|
+
* @param text - 字段的显示名称
|
|
222
|
+
* @returns 当前实例(支持链式调用)
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```typescript
|
|
226
|
+
* builder.label('用户邮箱');
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
label(text: string): this;
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* 自定义错误消息
|
|
233
|
+
* @param messages - 错误消息对象
|
|
234
|
+
* @returns 当前实例(支持链式调用)
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* ```typescript
|
|
238
|
+
* builder.messages({
|
|
239
|
+
* min: '至少{{#limit}}个字符',
|
|
240
|
+
* required: '这是必填项'
|
|
241
|
+
* });
|
|
242
|
+
* ```
|
|
243
|
+
*/
|
|
244
|
+
messages(messages: ErrorMessages): this;
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* 设置描述
|
|
248
|
+
* @param text - 字段描述文本
|
|
249
|
+
* @returns 当前实例(支持链式调用)
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* ```typescript
|
|
253
|
+
* builder.description('用户的注册邮箱');
|
|
254
|
+
* ```
|
|
255
|
+
*/
|
|
256
|
+
description(text: string): this;
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* 添加自定义验证器
|
|
260
|
+
* @param validator - 验证函数
|
|
261
|
+
* @returns 当前实例(支持链式调用)
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* ```typescript
|
|
265
|
+
* builder.custom((value) => {
|
|
266
|
+
* return value.includes('@');
|
|
267
|
+
* });
|
|
268
|
+
*
|
|
269
|
+
* // 异步验证
|
|
270
|
+
* builder.custom(async (value) => {
|
|
271
|
+
* const exists = await checkEmailExists(value);
|
|
272
|
+
* return !exists;
|
|
273
|
+
* });
|
|
274
|
+
*
|
|
275
|
+
* // 返回错误对象
|
|
276
|
+
* builder.custom((value) => {
|
|
277
|
+
* if (!value.includes('@')) {
|
|
278
|
+
* return { error: 'EMAIL_INVALID', message: '邮箱格式不正确' };
|
|
279
|
+
* }
|
|
280
|
+
* return true;
|
|
281
|
+
* });
|
|
282
|
+
* ```
|
|
283
|
+
*/
|
|
284
|
+
custom(validator: (value: any) => boolean | Promise<boolean> | { error: string; message: string }): this;
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* 条件验证
|
|
288
|
+
* @param refField - 参考字段
|
|
289
|
+
* @param options - 条件选项
|
|
290
|
+
* @returns 当前实例(支持链式调用)
|
|
291
|
+
*
|
|
292
|
+
* @example
|
|
293
|
+
* ```typescript
|
|
294
|
+
* // 当userType=admin时,email必填
|
|
295
|
+
* dsl({
|
|
296
|
+
* userType: 'string',
|
|
297
|
+
* email: 'email'.when('userType', {
|
|
298
|
+
* is: 'admin',
|
|
299
|
+
* then: dsl('email!'),
|
|
300
|
+
* otherwise: dsl('email')
|
|
301
|
+
* })
|
|
302
|
+
* });
|
|
303
|
+
* ```
|
|
304
|
+
*/
|
|
305
|
+
when(refField: string, options: {
|
|
306
|
+
is: any;
|
|
307
|
+
then: DslBuilder | JSONSchema;
|
|
308
|
+
otherwise?: DslBuilder | JSONSchema;
|
|
309
|
+
}): this;
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* 设置默认值
|
|
313
|
+
* @param value - 默认值
|
|
314
|
+
* @returns 当前实例(支持链式调用)
|
|
315
|
+
*
|
|
316
|
+
* @example
|
|
317
|
+
* ```typescript
|
|
318
|
+
* builder.default('user@example.com');
|
|
319
|
+
* ```
|
|
320
|
+
*/
|
|
321
|
+
default(value: any): this;
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* 转为JSON Schema
|
|
325
|
+
* @returns JSON Schema对象
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* ```typescript
|
|
329
|
+
* const schema = builder.toSchema();
|
|
330
|
+
* console.log(schema);
|
|
331
|
+
* // { type: 'string', format: 'email', ... }
|
|
332
|
+
* ```
|
|
333
|
+
*/
|
|
334
|
+
toSchema(): JSONSchema;
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* 验证数据
|
|
338
|
+
* @param data - 要验证的数据
|
|
339
|
+
* @param context - 验证上下文(可选)
|
|
340
|
+
* @returns 验证结果的Promise
|
|
341
|
+
*
|
|
342
|
+
* @example
|
|
343
|
+
* ```typescript
|
|
344
|
+
* const result = await builder.validate({ email: 'test@example.com' });
|
|
345
|
+
* if (result.valid) {
|
|
346
|
+
* console.log('验证通过');
|
|
347
|
+
* }
|
|
348
|
+
* ```
|
|
349
|
+
*/
|
|
350
|
+
validate(data: any, context?: any): Promise<ValidationResult>;
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* 用户名验证(自动设置合理约束)
|
|
354
|
+
* @param preset - 预设配置
|
|
355
|
+
* @returns 当前实例(支持链式调用)
|
|
356
|
+
*
|
|
357
|
+
* @example
|
|
358
|
+
* ```typescript
|
|
359
|
+
* // 预设方式
|
|
360
|
+
* builder.username('short'); // 3-16字符
|
|
361
|
+
* builder.username('medium'); // 3-32字符
|
|
362
|
+
* builder.username('long'); // 3-64字符
|
|
363
|
+
*
|
|
364
|
+
* // 范围字符串
|
|
365
|
+
* builder.username('5-20');
|
|
366
|
+
*
|
|
367
|
+
* // 详细配置
|
|
368
|
+
* builder.username({
|
|
369
|
+
* minLength: 5,
|
|
370
|
+
* maxLength: 20,
|
|
371
|
+
* allowUnderscore: true,
|
|
372
|
+
* allowNumber: true
|
|
373
|
+
* });
|
|
374
|
+
* ```
|
|
375
|
+
*/
|
|
376
|
+
username(preset?: 'short' | 'medium' | 'long' | string | { minLength?: number; maxLength?: number; allowUnderscore?: boolean; allowNumber?: boolean }): this;
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* 密码强度验证
|
|
380
|
+
* @param strength - 密码强度等级
|
|
381
|
+
* @returns 当前实例(支持链式调用)
|
|
382
|
+
*
|
|
383
|
+
* @example
|
|
384
|
+
* ```typescript
|
|
385
|
+
* builder.password('weak'); // 6+ 字符
|
|
386
|
+
* builder.password('medium'); // 8+ 字符,包含大小写
|
|
387
|
+
* builder.password('strong'); // 10+ 字符,包含大小写+数字
|
|
388
|
+
* builder.password('veryStrong'); // 12+ 字符,包含大小写+数字+特殊字符
|
|
389
|
+
* ```
|
|
390
|
+
*/
|
|
391
|
+
password(strength?: 'weak' | 'medium' | 'strong' | 'veryStrong'): this;
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* 手机号验证
|
|
395
|
+
* @param country - 国家代码
|
|
396
|
+
* @returns 当前实例(支持链式调用)
|
|
397
|
+
*
|
|
398
|
+
* @example
|
|
399
|
+
* ```typescript
|
|
400
|
+
* builder.phone('cn'); // 中国大陆 (11位)
|
|
401
|
+
* builder.phone('us'); // 美国
|
|
402
|
+
* builder.phone('hk'); // 香港
|
|
403
|
+
* builder.phone('tw'); // 台湾
|
|
404
|
+
* builder.phone('international'); // 国际号码
|
|
405
|
+
* ```
|
|
406
|
+
*/
|
|
407
|
+
phone(country?: 'cn' | 'us' | 'uk' | 'hk' | 'tw' | 'international'): this;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// ========== String 扩展 ==========
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* String 扩展全局接口
|
|
414
|
+
* 让字符串直接支持链式调用
|
|
415
|
+
*
|
|
416
|
+
* @example
|
|
417
|
+
* ```typescript
|
|
418
|
+
* const schema = dsl({
|
|
419
|
+
* email: 'email!'.pattern(/custom/).label('邮箱')
|
|
420
|
+
* });
|
|
421
|
+
* ```
|
|
422
|
+
*/
|
|
423
|
+
global {
|
|
424
|
+
interface String {
|
|
425
|
+
pattern(regex: RegExp | string, message?: string): DslBuilder;
|
|
426
|
+
label(text: string): DslBuilder;
|
|
427
|
+
messages(messages: ErrorMessages): DslBuilder;
|
|
428
|
+
description(text: string): DslBuilder;
|
|
429
|
+
custom(validator: (value: any) => boolean | Promise<boolean> | { error: string; message: string }): DslBuilder;
|
|
430
|
+
when(refField: string, options: { is: any; then: DslBuilder | JSONSchema; otherwise?: DslBuilder | JSONSchema }): DslBuilder;
|
|
431
|
+
default(value: any): DslBuilder;
|
|
432
|
+
toSchema(): JSONSchema;
|
|
433
|
+
/** 用户名验证 */
|
|
434
|
+
username(preset?: 'short' | 'medium' | 'long' | string): DslBuilder;
|
|
435
|
+
/** 密码强度验证 */
|
|
436
|
+
password(strength?: 'weak' | 'medium' | 'strong' | 'veryStrong'): DslBuilder;
|
|
437
|
+
/** 手机号验证 */
|
|
438
|
+
phone(country?: 'cn' | 'us' | 'uk' | 'hk' | 'tw' | 'international'): DslBuilder;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// ========== dsl() 函数 ==========
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* DSL 定义对象
|
|
446
|
+
*
|
|
447
|
+
* @description 支持多种类型的Schema定义
|
|
448
|
+
*/
|
|
449
|
+
export type DslDefinition = string | DslBuilder | {
|
|
450
|
+
[key: string]: DslDefinition;
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* SchemaIO 配置选项
|
|
455
|
+
*
|
|
456
|
+
* @description 用于配置验证器和错误消息的选项
|
|
457
|
+
*
|
|
458
|
+
* @example
|
|
459
|
+
* ```typescript
|
|
460
|
+
* const options: SchemaIOOptions = {
|
|
461
|
+
* allErrors: true,
|
|
462
|
+
* messages: {
|
|
463
|
+
* min: '至少需要 {{#limit}} 个字符',
|
|
464
|
+
* required: '这是必填项'
|
|
465
|
+
* },
|
|
466
|
+
* locale: 'zh-CN'
|
|
467
|
+
* };
|
|
468
|
+
* ```
|
|
469
|
+
*/
|
|
470
|
+
export interface SchemaIOOptions {
|
|
471
|
+
/** 是否返回所有错误(默认false,只返回第一个) */
|
|
472
|
+
allErrors?: boolean;
|
|
473
|
+
/** 是否启用详细模式 */
|
|
474
|
+
verbose?: boolean;
|
|
475
|
+
/** 自定义错误消息 */
|
|
476
|
+
messages?: ErrorMessages;
|
|
477
|
+
/** 语言代码 */
|
|
478
|
+
locale?: string;
|
|
479
|
+
/** 是否启用缓存 */
|
|
480
|
+
cache?: boolean;
|
|
481
|
+
/** 缓存大小限制 */
|
|
482
|
+
cacheSize?: number;
|
|
483
|
+
/** 扩展选项 */
|
|
484
|
+
[key: string]: any;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* dsl() 函数(主入口)
|
|
489
|
+
*
|
|
490
|
+
* @description SchemaIO的核心函数,用于创建Schema定义
|
|
491
|
+
*
|
|
492
|
+
* @example
|
|
493
|
+
* ```typescript
|
|
494
|
+
* // 1. 字符串:返回 DslBuilder(用于进一步配置)
|
|
495
|
+
* const builder = dsl('email!');
|
|
496
|
+
* builder.label('邮箱地址').messages({ required: '必填' });
|
|
497
|
+
*
|
|
498
|
+
* // 2. 对象:返回 SchemaIO 实例(用于验证)
|
|
499
|
+
* const schema = dsl({
|
|
500
|
+
* username: 'string:3-32!',
|
|
501
|
+
* email: 'email!',
|
|
502
|
+
* age: 'number:18-100'
|
|
503
|
+
* });
|
|
504
|
+
*
|
|
505
|
+
* // 3. 带选项的对象
|
|
506
|
+
* const schema = dsl({
|
|
507
|
+
* username: 'string:3-32!'
|
|
508
|
+
* }, {
|
|
509
|
+
* allErrors: true,
|
|
510
|
+
* messages: {
|
|
511
|
+
* min: '至少需要 {{#limit}} 个字符'
|
|
512
|
+
* }
|
|
513
|
+
* });
|
|
514
|
+
*
|
|
515
|
+
* // 4. 验证数据
|
|
516
|
+
* const result = schema.validate({ username: 'test' });
|
|
517
|
+
* ```
|
|
518
|
+
*/
|
|
519
|
+
export function dsl(definition: string): DslBuilder;
|
|
520
|
+
export function dsl(definition: Record<string, DslDefinition>, options?: SchemaIOOptions): SchemaIO;
|
|
521
|
+
export function dsl(definition: string | Record<string, DslDefinition>, options?: SchemaIOOptions): DslBuilder | SchemaIO;
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* SchemaIO 类
|
|
525
|
+
*
|
|
526
|
+
* @description 编译后的Schema实例,用于数据验证
|
|
527
|
+
*
|
|
528
|
+
* @example
|
|
529
|
+
* ```typescript
|
|
530
|
+
* const schema = dsl({
|
|
531
|
+
* username: 'string:3-32!',
|
|
532
|
+
* email: 'email!'
|
|
533
|
+
* });
|
|
534
|
+
*
|
|
535
|
+
* // 验证数据
|
|
536
|
+
* const result = schema.validate({ username: 'test', email: 'test@example.com' });
|
|
537
|
+
*
|
|
538
|
+
* // 快速验证(仅返回true/false)
|
|
539
|
+
* const isValid = schema.fastValidate(data);
|
|
540
|
+
*
|
|
541
|
+
* // 导出为JSON Schema
|
|
542
|
+
* const jsonSchema = schema.toJsonSchema();
|
|
543
|
+
*
|
|
544
|
+
* // 导出为数据库Schema
|
|
545
|
+
* const mongoSchema = schema.toMongoDB('users');
|
|
546
|
+
* const mysqlSchema = schema.toMySQL('users');
|
|
547
|
+
* ```
|
|
548
|
+
*/
|
|
549
|
+
export class SchemaIO {
|
|
550
|
+
/**
|
|
551
|
+
* 验证数据
|
|
552
|
+
* @param data - 要验证的数据
|
|
553
|
+
* @param options - 验证选项
|
|
554
|
+
* @returns 验证结果
|
|
555
|
+
*/
|
|
556
|
+
validate<T = any>(data: any, options?: ValidatorOptions): ValidationResult<T>;
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* 快速验证(仅返回布尔值)
|
|
560
|
+
* @param data - 要验证的数据
|
|
561
|
+
* @returns 是否通过验证
|
|
562
|
+
*/
|
|
563
|
+
fastValidate(data: any): boolean;
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* 转为JSON Schema
|
|
567
|
+
* @param options - 导出选项
|
|
568
|
+
* @returns JSON Schema对象
|
|
569
|
+
*/
|
|
570
|
+
toJsonSchema(options?: { version?: 'draft-04' | 'draft-06' | 'draft-07' }): JSONSchema;
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* 导出为MongoDB Schema
|
|
574
|
+
* @param collectionName - 集合名称
|
|
575
|
+
* @param options - 导出选项
|
|
576
|
+
* @returns MongoDB Schema定义
|
|
577
|
+
*/
|
|
578
|
+
toMongoDB(collectionName: string, options?: { strict?: boolean }): any;
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* 导出为MySQL Schema
|
|
582
|
+
* @param tableName - 表名
|
|
583
|
+
* @param options - 导出选项
|
|
584
|
+
* @returns MySQL CREATE TABLE语句
|
|
585
|
+
*/
|
|
586
|
+
toMySQL(tableName: string, options?: { engine?: string; charset?: string }): string;
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* 导出为PostgreSQL Schema
|
|
590
|
+
* @param tableName - 表名
|
|
591
|
+
* @param options - 导出选项
|
|
592
|
+
* @returns PostgreSQL CREATE TABLE语句
|
|
593
|
+
*/
|
|
594
|
+
toPostgreSQL(tableName: string, options?: any): string;
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* 清理缓存
|
|
598
|
+
*/
|
|
599
|
+
clearCache(): void;
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* 获取缓存统计
|
|
603
|
+
* @returns 缓存统计信息
|
|
604
|
+
*/
|
|
605
|
+
getCacheStats(): { hits: number; misses: number; size: number };
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* 编译Schema(预热)
|
|
609
|
+
*/
|
|
610
|
+
compile(): void;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* 全局配置
|
|
615
|
+
*
|
|
616
|
+
* @description dsl命名空间的全局配置和工具方法
|
|
617
|
+
*/
|
|
618
|
+
export namespace dsl {
|
|
619
|
+
/**
|
|
620
|
+
* 全局配置
|
|
621
|
+
*
|
|
622
|
+
* @description 配置全局的验证规则和语言包
|
|
623
|
+
*
|
|
624
|
+
* @example
|
|
625
|
+
* ```typescript
|
|
626
|
+
* dsl.config({
|
|
627
|
+
* // 自定义手机号规则
|
|
628
|
+
* patterns: {
|
|
629
|
+
* phone: {
|
|
630
|
+
* cn: {
|
|
631
|
+
* pattern: /^1[3-9]\d{9}$/,
|
|
632
|
+
* min: 11,
|
|
633
|
+
* max: 11,
|
|
634
|
+
* key: 'phone.cn'
|
|
635
|
+
* }
|
|
636
|
+
* }
|
|
637
|
+
* },
|
|
638
|
+
* // 设置语言包
|
|
639
|
+
* locales: 'zh-CN'
|
|
640
|
+
* });
|
|
641
|
+
* ```
|
|
642
|
+
*/
|
|
643
|
+
export function config(options: {
|
|
644
|
+
/** 自定义验证规则 */
|
|
645
|
+
patterns?: {
|
|
646
|
+
/** 手机号规则 */
|
|
647
|
+
phone?: Record<string, { pattern: RegExp; min?: number; max?: number; key?: string }>;
|
|
648
|
+
/** 身份证号规则 */
|
|
649
|
+
idCard?: Record<string, { pattern: RegExp; min?: number; max?: number; key?: string }>;
|
|
650
|
+
/** 信用卡号规则 */
|
|
651
|
+
creditCard?: Record<string, { pattern: RegExp; msg?: string }>;
|
|
652
|
+
};
|
|
653
|
+
/** 手机号规则(兼容旧版) */
|
|
654
|
+
phone?: Record<string, { pattern: RegExp; min?: number; max?: number; key?: string }>;
|
|
655
|
+
/** 语言包配置 */
|
|
656
|
+
locales?: Record<string, ErrorMessages> | string;
|
|
657
|
+
}): void;
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* 匹配规则
|
|
661
|
+
*
|
|
662
|
+
* @description 根据值匹配不同的Schema定义
|
|
663
|
+
*
|
|
664
|
+
* @example
|
|
665
|
+
* ```typescript
|
|
666
|
+
* const schema = dsl({
|
|
667
|
+
* userType: 'string',
|
|
668
|
+
* profile: dsl.match('userType', {
|
|
669
|
+
* 'admin': { role: 'string!', permissions: 'array' },
|
|
670
|
+
* 'user': { bio: 'string' }
|
|
671
|
+
* })
|
|
672
|
+
* });
|
|
673
|
+
* ```
|
|
674
|
+
*/
|
|
675
|
+
export function match(value: any, cases: Record<string, any>): any;
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* 条件规则
|
|
679
|
+
*
|
|
680
|
+
* @description 根据条件选择不同的Schema(JavaScript中使用 dsl.if)
|
|
681
|
+
*
|
|
682
|
+
* @example
|
|
683
|
+
* ```typescript
|
|
684
|
+
* const schema = dsl({
|
|
685
|
+
* age: 'number',
|
|
686
|
+
* license: dsl._if(
|
|
687
|
+
* (data) => data.age >= 18,
|
|
688
|
+
* { hasLicense: 'boolean!' },
|
|
689
|
+
* { hasLicense: 'boolean' }
|
|
690
|
+
* )
|
|
691
|
+
* });
|
|
692
|
+
* ```
|
|
693
|
+
*/
|
|
694
|
+
export const _if: (condition: any, thenSchema: any, elseSchema?: any) => any;
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* 设置默认语言
|
|
698
|
+
*
|
|
699
|
+
* @param locale - 语言代码
|
|
700
|
+
*
|
|
701
|
+
* @example
|
|
702
|
+
* ```typescript
|
|
703
|
+
* dsl.setLocale('zh-CN');
|
|
704
|
+
* dsl.setLocale('en-US');
|
|
705
|
+
* ```
|
|
706
|
+
*/
|
|
707
|
+
export function setLocale(locale: string): void;
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* 获取当前语言
|
|
711
|
+
*
|
|
712
|
+
* @returns 当前语言代码
|
|
713
|
+
*/
|
|
714
|
+
export function getLocale(): string;
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* 获取可用的语言列表
|
|
718
|
+
*
|
|
719
|
+
* @returns 语言代码数组
|
|
720
|
+
*/
|
|
721
|
+
export function getLocales(): string[];
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* 添加自定义语言包
|
|
725
|
+
*
|
|
726
|
+
* @param locale - 语言代码
|
|
727
|
+
* @param messages - 错误消息
|
|
728
|
+
*
|
|
729
|
+
* @example
|
|
730
|
+
* ```typescript
|
|
731
|
+
* dsl.addMessages('ja-JP', {
|
|
732
|
+
* required: '必須項目です',
|
|
733
|
+
* min: '{{#limit}}文字以上必要です'
|
|
734
|
+
* });
|
|
735
|
+
* ```
|
|
736
|
+
*/
|
|
737
|
+
export function addMessages(locale: string, messages: ErrorMessages): void;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// ========== Validator 类 ==========
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* Validator 选项
|
|
744
|
+
*
|
|
745
|
+
* @description 验证器的配置选项
|
|
746
|
+
*/
|
|
747
|
+
export interface ValidatorOptions {
|
|
748
|
+
/** 是否返回所有错误 */
|
|
749
|
+
allErrors?: boolean;
|
|
750
|
+
/** 是否启用详细模式 */
|
|
751
|
+
verbose?: boolean;
|
|
752
|
+
/** 自定义格式验证 */
|
|
753
|
+
formats?: Record<string, RegExp | ((value: any) => boolean)>;
|
|
754
|
+
/** 严格模式 */
|
|
755
|
+
strict?: boolean;
|
|
756
|
+
/** 扩展选项 */
|
|
757
|
+
[key: string]: any;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/**
|
|
761
|
+
* 验证器类
|
|
762
|
+
*
|
|
763
|
+
* @description 基于ajv的JSON Schema验证器
|
|
764
|
+
*
|
|
765
|
+
* @example
|
|
766
|
+
* ```typescript
|
|
767
|
+
* // 创建验证器
|
|
768
|
+
* const validator = new Validator({ allErrors: true });
|
|
769
|
+
*
|
|
770
|
+
* // 验证数据
|
|
771
|
+
* const schema = dsl({ email: 'email!' }).toJsonSchema();
|
|
772
|
+
* const result = validator.validate(schema, { email: 'test@example.com' });
|
|
773
|
+
*
|
|
774
|
+
* if (result.valid) {
|
|
775
|
+
* console.log('验证通过');
|
|
776
|
+
* } else {
|
|
777
|
+
* console.log('错误:', result.errors);
|
|
778
|
+
* }
|
|
779
|
+
*
|
|
780
|
+
* // 获取底层ajv实例
|
|
781
|
+
* const ajv = validator.getAjv();
|
|
782
|
+
* ```
|
|
783
|
+
*/
|
|
784
|
+
export class Validator {
|
|
785
|
+
/**
|
|
786
|
+
* 构造函数
|
|
787
|
+
* @param options - 验证器选项
|
|
788
|
+
*/
|
|
789
|
+
constructor(options?: ValidatorOptions);
|
|
790
|
+
|
|
791
|
+
/**
|
|
792
|
+
* 验证数据
|
|
793
|
+
* @param schema - JSON Schema对象
|
|
794
|
+
* @param data - 要验证的数据
|
|
795
|
+
* @returns 验证结果
|
|
796
|
+
*/
|
|
797
|
+
validate<T = any>(schema: JSONSchema, data: any): ValidationResult<T>;
|
|
798
|
+
|
|
799
|
+
/**
|
|
800
|
+
* 获取底层ajv实例
|
|
801
|
+
* @returns ajv实例
|
|
802
|
+
*/
|
|
803
|
+
getAjv(): any;
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* 添加自定义格式
|
|
807
|
+
* @param name - 格式名称
|
|
808
|
+
* @param validator - 验证函数或正则表达式
|
|
809
|
+
*
|
|
810
|
+
* @example
|
|
811
|
+
* ```typescript
|
|
812
|
+
* validator.addFormat('phone-cn', /^1[3-9]\d{9}$/);
|
|
813
|
+
* validator.addFormat('custom', (value) => {
|
|
814
|
+
* return value.startsWith('prefix-');
|
|
815
|
+
* });
|
|
816
|
+
* ```
|
|
817
|
+
*/
|
|
818
|
+
addFormat(name: string, validator: RegExp | ((value: any) => boolean)): void;
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* 添加自定义关键字
|
|
822
|
+
* @param keyword - 关键字名称
|
|
823
|
+
* @param definition - 关键字定义
|
|
824
|
+
*/
|
|
825
|
+
addKeyword(keyword: string, definition: any): void;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* 便捷验证方法(推荐)
|
|
830
|
+
*
|
|
831
|
+
* @description 使用默认的单例Validator,无需new
|
|
832
|
+
*
|
|
833
|
+
* @example
|
|
834
|
+
* ```typescript
|
|
835
|
+
* import { dsl, validate } from 'schema-dsl';
|
|
836
|
+
*
|
|
837
|
+
* const schema = dsl({ email: 'email!' });
|
|
838
|
+
* const result = validate(schema, { email: 'test@example.com' });
|
|
839
|
+
*
|
|
840
|
+
* if (result.valid) {
|
|
841
|
+
* console.log('验证通过');
|
|
842
|
+
* }
|
|
843
|
+
* ```
|
|
844
|
+
*/
|
|
845
|
+
export function validate<T = any>(schema: JSONSchema | SchemaIO, data: any): ValidationResult<T>;
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* 获取默认Validator实例(单例)
|
|
849
|
+
*
|
|
850
|
+
* @description 获取全局共享的Validator实例
|
|
851
|
+
*
|
|
852
|
+
* @example
|
|
853
|
+
* ```typescript
|
|
854
|
+
* import { getDefaultValidator } from 'schema-dsl';
|
|
855
|
+
*
|
|
856
|
+
* const validator = getDefaultValidator();
|
|
857
|
+
* validator.addFormat('custom', /pattern/);
|
|
858
|
+
* ```
|
|
859
|
+
*/
|
|
860
|
+
export function getDefaultValidator(): Validator;
|
|
861
|
+
|
|
862
|
+
// ========== 导出器 ==========
|
|
863
|
+
|
|
864
|
+
/**
|
|
865
|
+
* MongoDB 导出器选项
|
|
866
|
+
*/
|
|
867
|
+
export interface MongoDBExporterOptions {
|
|
868
|
+
/** 严格模式(默认false) */
|
|
869
|
+
strict?: boolean;
|
|
870
|
+
/** 时间戳字段 */
|
|
871
|
+
timestamps?: boolean;
|
|
872
|
+
/** 集合名称 */
|
|
873
|
+
collectionName?: string;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
/**
|
|
877
|
+
* MongoDB 导出器
|
|
878
|
+
*
|
|
879
|
+
* @description 将JSON Schema导出为MongoDB验证规则
|
|
880
|
+
*
|
|
881
|
+
* @example
|
|
882
|
+
* ```typescript
|
|
883
|
+
* const exporter = new MongoDBExporter({ strict: true });
|
|
884
|
+
* const mongoSchema = exporter.export(jsonSchema);
|
|
885
|
+
*
|
|
886
|
+
* // 生成MongoDB命令
|
|
887
|
+
* const command = exporter.generateCommand('users', jsonSchema);
|
|
888
|
+
* console.log(command);
|
|
889
|
+
* // db.createCollection("users", { validator: { $jsonSchema: {...} } })
|
|
890
|
+
* ```
|
|
891
|
+
*/
|
|
892
|
+
export class MongoDBExporter {
|
|
893
|
+
/**
|
|
894
|
+
* 构造函数
|
|
895
|
+
* @param options - 导出选项
|
|
896
|
+
*/
|
|
897
|
+
constructor(options?: MongoDBExporterOptions);
|
|
898
|
+
|
|
899
|
+
/**
|
|
900
|
+
* 导出为MongoDB Schema
|
|
901
|
+
* @param schema - JSON Schema对象
|
|
902
|
+
* @returns MongoDB验证规则
|
|
903
|
+
*/
|
|
904
|
+
export(schema: JSONSchema): any;
|
|
905
|
+
|
|
906
|
+
/**
|
|
907
|
+
* 生成MongoDB创建集合命令
|
|
908
|
+
* @param collectionName - 集合名称
|
|
909
|
+
* @param schema - JSON Schema对象
|
|
910
|
+
* @returns MongoDB命令字符串
|
|
911
|
+
*/
|
|
912
|
+
generateCommand(collectionName: string, schema: JSONSchema): string;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
/**
|
|
916
|
+
* MySQL 导出器选项
|
|
917
|
+
*/
|
|
918
|
+
export interface MySQLExporterOptions {
|
|
919
|
+
/** 表名 */
|
|
920
|
+
tableName?: string;
|
|
921
|
+
/** 存储引擎(默认InnoDB) */
|
|
922
|
+
engine?: string;
|
|
923
|
+
/** 字符集(默认utf8mb4) */
|
|
924
|
+
charset?: string;
|
|
925
|
+
/** 排序规则 */
|
|
926
|
+
collation?: string;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
/**
|
|
930
|
+
* MySQL 导出器
|
|
931
|
+
*
|
|
932
|
+
* @description 将JSON Schema导出为MySQL CREATE TABLE语句
|
|
933
|
+
*
|
|
934
|
+
* @example
|
|
935
|
+
* ```typescript
|
|
936
|
+
* const exporter = new MySQLExporter();
|
|
937
|
+
* const sql = exporter.export(jsonSchema, {
|
|
938
|
+
* tableName: 'users',
|
|
939
|
+
* engine: 'InnoDB',
|
|
940
|
+
* charset: 'utf8mb4'
|
|
941
|
+
* });
|
|
942
|
+
*
|
|
943
|
+
* console.log(sql);
|
|
944
|
+
* // CREATE TABLE `users` (
|
|
945
|
+
* // `id` INT PRIMARY KEY AUTO_INCREMENT,
|
|
946
|
+
* // `username` VARCHAR(32) NOT NULL,
|
|
947
|
+
* // ...
|
|
948
|
+
* // ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
949
|
+
* ```
|
|
950
|
+
*/
|
|
951
|
+
export class MySQLExporter {
|
|
952
|
+
/**
|
|
953
|
+
* 构造函数
|
|
954
|
+
*/
|
|
955
|
+
constructor();
|
|
956
|
+
|
|
957
|
+
/**
|
|
958
|
+
* 导出为MySQL CREATE TABLE语句
|
|
959
|
+
* @param schema - JSON Schema对象
|
|
960
|
+
* @param options - 导出选项
|
|
961
|
+
* @returns SQL语句
|
|
962
|
+
*/
|
|
963
|
+
export(schema: JSONSchema, options?: MySQLExporterOptions): string;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
/**
|
|
967
|
+
* PostgreSQL 导出器选项
|
|
968
|
+
*/
|
|
969
|
+
export interface PostgreSQLExporterOptions {
|
|
970
|
+
/** 表名 */
|
|
971
|
+
tableName?: string;
|
|
972
|
+
/** 模式名 */
|
|
973
|
+
schemaName?: string;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
/**
|
|
977
|
+
* PostgreSQL 导出器
|
|
978
|
+
*
|
|
979
|
+
* @description 将JSON Schema导出为PostgreSQL CREATE TABLE语句
|
|
980
|
+
*
|
|
981
|
+
* @example
|
|
982
|
+
* ```typescript
|
|
983
|
+
* const exporter = new PostgreSQLExporter();
|
|
984
|
+
* const sql = exporter.export(jsonSchema, {
|
|
985
|
+
* tableName: 'users',
|
|
986
|
+
* schemaName: 'public'
|
|
987
|
+
* });
|
|
988
|
+
*
|
|
989
|
+
* console.log(sql);
|
|
990
|
+
* // CREATE TABLE public.users (
|
|
991
|
+
* // id SERIAL PRIMARY KEY,
|
|
992
|
+
* // username VARCHAR(32) NOT NULL,
|
|
993
|
+
* // ...
|
|
994
|
+
* // );
|
|
995
|
+
* ```
|
|
996
|
+
*/
|
|
997
|
+
export class PostgreSQLExporter {
|
|
998
|
+
/**
|
|
999
|
+
* 构造函数
|
|
1000
|
+
*/
|
|
1001
|
+
constructor();
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* 导出为PostgreSQL CREATE TABLE语句
|
|
1005
|
+
* @param schema - JSON Schema对象
|
|
1006
|
+
* @param options - 导出选项
|
|
1007
|
+
* @returns SQL语句
|
|
1008
|
+
*/
|
|
1009
|
+
export(schema: JSONSchema, options?: PostgreSQLExporterOptions): string;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
/**
|
|
1013
|
+
* 导出器命名空间
|
|
1014
|
+
*
|
|
1015
|
+
* @description 统一的导出器访问入口
|
|
1016
|
+
*
|
|
1017
|
+
* @example
|
|
1018
|
+
* ```typescript
|
|
1019
|
+
* import { exporters } from 'schema-dsl';
|
|
1020
|
+
*
|
|
1021
|
+
* const mongoExporter = new exporters.MongoDBExporter();
|
|
1022
|
+
* const mysqlExporter = new exporters.MySQLExporter();
|
|
1023
|
+
* const pgExporter = new exporters.PostgreSQLExporter();
|
|
1024
|
+
* ```
|
|
1025
|
+
*/
|
|
1026
|
+
|
|
1027
|
+
// ========== 工具函数 ==========
|
|
1028
|
+
|
|
1029
|
+
/**
|
|
1030
|
+
* 类型转换工具
|
|
1031
|
+
*
|
|
1032
|
+
* @description 提供多种Schema类型之间的转换
|
|
1033
|
+
*
|
|
1034
|
+
* @example
|
|
1035
|
+
* ```typescript
|
|
1036
|
+
* // 转换为JSON Schema类型
|
|
1037
|
+
* const jsonType = TypeConverter.toJSONSchemaType('email');
|
|
1038
|
+
* // { type: 'string', format: 'email' }
|
|
1039
|
+
*
|
|
1040
|
+
* // 转换为MongoDB类型
|
|
1041
|
+
* const mongoType = TypeConverter.toMongoDBType('string');
|
|
1042
|
+
* // 'String'
|
|
1043
|
+
*
|
|
1044
|
+
* // 转换为MySQL类型
|
|
1045
|
+
* const mysqlType = TypeConverter.toMySQLType('string', { maxLength: 255 });
|
|
1046
|
+
* // 'VARCHAR(255)'
|
|
1047
|
+
* ```
|
|
1048
|
+
*/
|
|
1049
|
+
export class TypeConverter {
|
|
1050
|
+
/**
|
|
1051
|
+
* 转换为JSON Schema类型
|
|
1052
|
+
* @param simpleType - 简单类型名称
|
|
1053
|
+
* @returns JSON Schema类型对象
|
|
1054
|
+
*/
|
|
1055
|
+
static toJSONSchemaType(simpleType: string): JSONSchema;
|
|
1056
|
+
|
|
1057
|
+
/**
|
|
1058
|
+
* 转换为MongoDB类型
|
|
1059
|
+
* @param jsonSchemaType - JSON Schema类型
|
|
1060
|
+
* @returns MongoDB类型字符串
|
|
1061
|
+
*/
|
|
1062
|
+
static toMongoDBType(jsonSchemaType: string): string;
|
|
1063
|
+
|
|
1064
|
+
/**
|
|
1065
|
+
* 转换为MySQL类型
|
|
1066
|
+
* @param jsonSchemaType - JSON Schema类型
|
|
1067
|
+
* @param constraints - 约束条件
|
|
1068
|
+
* @returns MySQL类型字符串
|
|
1069
|
+
*/
|
|
1070
|
+
static toMySQLType(jsonSchemaType: string, constraints?: Record<string, any>): string;
|
|
1071
|
+
|
|
1072
|
+
/**
|
|
1073
|
+
* 转换为PostgreSQL类型
|
|
1074
|
+
* @param jsonSchemaType - JSON Schema类型
|
|
1075
|
+
* @param constraints - 约束条件
|
|
1076
|
+
* @returns PostgreSQL类型字符串
|
|
1077
|
+
*/
|
|
1078
|
+
static toPostgreSQLType(jsonSchemaType: string, constraints?: Record<string, any>): string;
|
|
1079
|
+
|
|
1080
|
+
/**
|
|
1081
|
+
* 规范化属性名
|
|
1082
|
+
* @param name - 原属性名
|
|
1083
|
+
* @param style - 命名风格
|
|
1084
|
+
* @returns 规范化后的属性名
|
|
1085
|
+
*
|
|
1086
|
+
* @example
|
|
1087
|
+
* ```typescript
|
|
1088
|
+
* TypeConverter.normalizePropertyName('userName', 'snake_case');
|
|
1089
|
+
* // 'user_name'
|
|
1090
|
+
*
|
|
1091
|
+
* TypeConverter.normalizePropertyName('user_name', 'camelCase');
|
|
1092
|
+
* // 'userName'
|
|
1093
|
+
* ```
|
|
1094
|
+
*/
|
|
1095
|
+
static normalizePropertyName(name: string, style?: 'snake_case' | 'camelCase'): string;
|
|
1096
|
+
|
|
1097
|
+
/**
|
|
1098
|
+
* 将format转换为正则表达式
|
|
1099
|
+
* @param format - 格式名称
|
|
1100
|
+
* @returns 正则表达式字符串或null
|
|
1101
|
+
*/
|
|
1102
|
+
static formatToRegex(format: string): string | null;
|
|
1103
|
+
|
|
1104
|
+
/**
|
|
1105
|
+
* 合并Schema
|
|
1106
|
+
* @param base - 基础Schema
|
|
1107
|
+
* @param override - 覆盖Schema
|
|
1108
|
+
* @returns 合并后的Schema
|
|
1109
|
+
*/
|
|
1110
|
+
static mergeSchemas(base: JSONSchema, override: JSONSchema): JSONSchema;
|
|
1111
|
+
|
|
1112
|
+
/**
|
|
1113
|
+
* 提取约束条件
|
|
1114
|
+
* @param schema - JSON Schema对象
|
|
1115
|
+
* @returns 约束条件对象
|
|
1116
|
+
*/
|
|
1117
|
+
static extractConstraints(schema: JSONSchema): Record<string, any>;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
/**
|
|
1121
|
+
* Schema 辅助工具
|
|
1122
|
+
*
|
|
1123
|
+
* @description 提供Schema的基础操作方法
|
|
1124
|
+
*
|
|
1125
|
+
* @example
|
|
1126
|
+
* ```typescript
|
|
1127
|
+
* // 合并Schema
|
|
1128
|
+
* const merged = SchemaHelper.merge(schema1, schema2);
|
|
1129
|
+
*
|
|
1130
|
+
* // 克隆Schema
|
|
1131
|
+
* const cloned = SchemaHelper.clone(schema);
|
|
1132
|
+
* ```
|
|
1133
|
+
*/
|
|
1134
|
+
export class SchemaHelper {
|
|
1135
|
+
/**
|
|
1136
|
+
* 合并多个Schema
|
|
1137
|
+
* @param schema1 - 第一个Schema
|
|
1138
|
+
* @param schema2 - 第二个Schema
|
|
1139
|
+
* @returns 合并后的Schema
|
|
1140
|
+
*/
|
|
1141
|
+
static merge(schema1: JSONSchema, schema2: JSONSchema): JSONSchema;
|
|
1142
|
+
|
|
1143
|
+
/**
|
|
1144
|
+
* 克隆Schema
|
|
1145
|
+
* @param schema - 要克隆的Schema
|
|
1146
|
+
* @returns 克隆的Schema副本
|
|
1147
|
+
*/
|
|
1148
|
+
static clone(schema: JSONSchema): JSONSchema;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
/**
|
|
1152
|
+
* Schema 工具类 (v2.0.1+)
|
|
1153
|
+
*
|
|
1154
|
+
* @description 提供高级Schema操作和工具方法
|
|
1155
|
+
*
|
|
1156
|
+
* @example
|
|
1157
|
+
* ```typescript
|
|
1158
|
+
* // 创建可复用的Schema片段
|
|
1159
|
+
* const addressFragment = SchemaUtils.reusable(() => ({
|
|
1160
|
+
* city: 'string!',
|
|
1161
|
+
* street: 'string!',
|
|
1162
|
+
* zip: 'string'
|
|
1163
|
+
* }));
|
|
1164
|
+
*
|
|
1165
|
+
* // 创建Schema库
|
|
1166
|
+
* const library = SchemaUtils.createLibrary({
|
|
1167
|
+
* user: () => ({ username: 'string!', email: 'email!' }),
|
|
1168
|
+
* address: addressFragment
|
|
1169
|
+
* });
|
|
1170
|
+
*
|
|
1171
|
+
* // 使用Schema库
|
|
1172
|
+
* const schema = dsl({
|
|
1173
|
+
* user: library.user(),
|
|
1174
|
+
* address: library.address()
|
|
1175
|
+
* });
|
|
1176
|
+
* ```
|
|
1177
|
+
*/
|
|
1178
|
+
export class SchemaUtils {
|
|
1179
|
+
/**
|
|
1180
|
+
* 创建可复用的Schema片段
|
|
1181
|
+
* @param factory - Schema工厂函数
|
|
1182
|
+
* @returns 可复用的工厂函数
|
|
1183
|
+
*/
|
|
1184
|
+
static reusable<T>(factory: () => T): () => T;
|
|
1185
|
+
|
|
1186
|
+
/**
|
|
1187
|
+
* 创建Schema片段库
|
|
1188
|
+
* @param fragments - Schema片段对象
|
|
1189
|
+
* @returns Schema库对象
|
|
1190
|
+
*/
|
|
1191
|
+
static createLibrary<T extends Record<string, () => any>>(fragments: T): T;
|
|
1192
|
+
|
|
1193
|
+
/**
|
|
1194
|
+
* 合并多个Schema
|
|
1195
|
+
* @param schemas - 要合并的Schema数组
|
|
1196
|
+
* @returns 合并后的Schema
|
|
1197
|
+
*/
|
|
1198
|
+
static merge(...schemas: JSONSchema[]): JSONSchema;
|
|
1199
|
+
|
|
1200
|
+
/**
|
|
1201
|
+
* 扩展Schema
|
|
1202
|
+
* @param baseSchema - 基础Schema
|
|
1203
|
+
* @param extensions - 扩展字段
|
|
1204
|
+
* @returns 扩展后的Schema
|
|
1205
|
+
*/
|
|
1206
|
+
static extend(baseSchema: JSONSchema, extensions: Record<string, any>): JSONSchema;
|
|
1207
|
+
|
|
1208
|
+
/**
|
|
1209
|
+
* 挑选Schema的部分字段
|
|
1210
|
+
* @param schema - 原Schema
|
|
1211
|
+
* @param fields - 要挑选的字段列表
|
|
1212
|
+
* @returns 新Schema
|
|
1213
|
+
*
|
|
1214
|
+
* @example
|
|
1215
|
+
* ```typescript
|
|
1216
|
+
* const userSchema = dsl({
|
|
1217
|
+
* username: 'string!',
|
|
1218
|
+
* email: 'email!',
|
|
1219
|
+
* password: 'string!',
|
|
1220
|
+
* age: 'number'
|
|
1221
|
+
* });
|
|
1222
|
+
*
|
|
1223
|
+
* const loginSchema = SchemaUtils.pick(userSchema, ['username', 'password']);
|
|
1224
|
+
* ```
|
|
1225
|
+
*/
|
|
1226
|
+
static pick(schema: JSONSchema, fields: string[]): JSONSchema;
|
|
1227
|
+
|
|
1228
|
+
/**
|
|
1229
|
+
* 排除Schema的部分字段
|
|
1230
|
+
* @param schema - 原Schema
|
|
1231
|
+
* @param fields - 要排除的字段列表
|
|
1232
|
+
* @returns 新Schema
|
|
1233
|
+
*
|
|
1234
|
+
* @example
|
|
1235
|
+
* ```typescript
|
|
1236
|
+
* const publicUserSchema = SchemaUtils.omit(userSchema, ['password']);
|
|
1237
|
+
* ```
|
|
1238
|
+
*/
|
|
1239
|
+
static omit(schema: JSONSchema, fields: string[]): JSONSchema;
|
|
1240
|
+
|
|
1241
|
+
/**
|
|
1242
|
+
* 创建带性能监控的Validator
|
|
1243
|
+
* @param validator - 原Validator实例
|
|
1244
|
+
* @returns 包装后的Validator
|
|
1245
|
+
*/
|
|
1246
|
+
static withPerformance(validator: Validator): Validator;
|
|
1247
|
+
|
|
1248
|
+
/**
|
|
1249
|
+
* 批量验证
|
|
1250
|
+
* @param schema - JSON Schema对象
|
|
1251
|
+
* @param dataArray - 数据数组
|
|
1252
|
+
* @param validator - Validator实例
|
|
1253
|
+
* @returns 批量验证结果
|
|
1254
|
+
*
|
|
1255
|
+
* @example
|
|
1256
|
+
* ```typescript
|
|
1257
|
+
* const results = SchemaUtils.validateBatch(
|
|
1258
|
+
* schema,
|
|
1259
|
+
* [data1, data2, data3],
|
|
1260
|
+
* validator
|
|
1261
|
+
* );
|
|
1262
|
+
*
|
|
1263
|
+
* console.log(results.summary);
|
|
1264
|
+
* // {
|
|
1265
|
+
* // total: 3,
|
|
1266
|
+
* // valid: 2,
|
|
1267
|
+
* // invalid: 1,
|
|
1268
|
+
* // duration: 15,
|
|
1269
|
+
* // averageTime: 5
|
|
1270
|
+
* // }
|
|
1271
|
+
* ```
|
|
1272
|
+
*/
|
|
1273
|
+
static validateBatch(schema: JSONSchema, dataArray: any[], validator: Validator): {
|
|
1274
|
+
results: Array<{ index: number; valid: boolean; errors: any; data: any }>;
|
|
1275
|
+
summary: { total: number; valid: number; invalid: number; duration: number; averageTime: number };
|
|
1276
|
+
};
|
|
1277
|
+
|
|
1278
|
+
/**
|
|
1279
|
+
* 检查嵌套深度
|
|
1280
|
+
* @param schema - JSON Schema对象
|
|
1281
|
+
* @param maxDepth - 最大深度(默认10)
|
|
1282
|
+
* @returns 检查结果
|
|
1283
|
+
*/
|
|
1284
|
+
static validateNestingDepth(schema: JSONSchema, maxDepth?: number): {
|
|
1285
|
+
valid: boolean;
|
|
1286
|
+
depth: number;
|
|
1287
|
+
path: string;
|
|
1288
|
+
message: string;
|
|
1289
|
+
};
|
|
1290
|
+
|
|
1291
|
+
/**
|
|
1292
|
+
* 导出为Markdown文档
|
|
1293
|
+
* @param schema - JSON Schema对象
|
|
1294
|
+
* @param options - 导出选项
|
|
1295
|
+
* @returns Markdown字符串
|
|
1296
|
+
*/
|
|
1297
|
+
static toMarkdown(schema: JSONSchema, options?: { title?: string; locale?: string }): string;
|
|
1298
|
+
|
|
1299
|
+
/**
|
|
1300
|
+
* 导出为HTML文档
|
|
1301
|
+
* @param schema - JSON Schema对象
|
|
1302
|
+
* @param options - 导出选项
|
|
1303
|
+
* @returns HTML字符串
|
|
1304
|
+
*/
|
|
1305
|
+
static toHTML(schema: JSONSchema, options?: { title?: string }): string;
|
|
1306
|
+
|
|
1307
|
+
/**
|
|
1308
|
+
* 克隆Schema
|
|
1309
|
+
* @param schema - 要克隆的Schema
|
|
1310
|
+
* @returns Schema副本
|
|
1311
|
+
*/
|
|
1312
|
+
static clone(schema: JSONSchema): JSONSchema;
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
// ========== 错误代码 ==========
|
|
1316
|
+
|
|
1317
|
+
/**
|
|
1318
|
+
* 错误代码常量
|
|
1319
|
+
*
|
|
1320
|
+
* @description 预定义的错误代码和消息
|
|
1321
|
+
*
|
|
1322
|
+
* @example
|
|
1323
|
+
* ```typescript
|
|
1324
|
+
* import { ErrorCodes } from 'schema-dsl';
|
|
1325
|
+
*
|
|
1326
|
+
* console.log(ErrorCodes.min);
|
|
1327
|
+
* // { code: 'MIN_LENGTH', message: 'Must be at least {{#limit}} characters', zhCN: '至少需要 {{#limit}} 个字符' }
|
|
1328
|
+
*
|
|
1329
|
+
* console.log(ErrorCodes.email);
|
|
1330
|
+
* // { code: 'INVALID_EMAIL', message: 'Invalid email format', zhCN: '邮箱格式不正确' }
|
|
1331
|
+
* ```
|
|
1332
|
+
*/
|
|
1333
|
+
export const ErrorCodes: {
|
|
1334
|
+
/** 最小长度/最小值错误 */
|
|
1335
|
+
min: { code: string; message: string; zhCN: string };
|
|
1336
|
+
/** 最大长度/最大值错误 */
|
|
1337
|
+
max: { code: string; message: string; zhCN: string };
|
|
1338
|
+
/** 邮箱格式错误 */
|
|
1339
|
+
email: { code: string; message: string; zhCN: string };
|
|
1340
|
+
/** URL格式错误 */
|
|
1341
|
+
url: { code: string; message: string; zhCN: string };
|
|
1342
|
+
/** 正则表达式验证错误 */
|
|
1343
|
+
pattern: { code: string; message: string; zhCN: string };
|
|
1344
|
+
/** 必填项错误 */
|
|
1345
|
+
required: { code: string; message: string; zhCN: string };
|
|
1346
|
+
/** 类型错误 */
|
|
1347
|
+
type: { code: string; message: string; zhCN: string };
|
|
1348
|
+
/** 枚举值错误 */
|
|
1349
|
+
enum: { code: string; message: string; zhCN: string };
|
|
1350
|
+
};
|
|
1351
|
+
|
|
1352
|
+
// ========== 多语言 ==========
|
|
1353
|
+
|
|
1354
|
+
/**
|
|
1355
|
+
* 多语言支持
|
|
1356
|
+
*
|
|
1357
|
+
* @description 提供国际化支持的工具类
|
|
1358
|
+
*
|
|
1359
|
+
* @example
|
|
1360
|
+
* ```typescript
|
|
1361
|
+
* import { Locale } from 'schema-dsl';
|
|
1362
|
+
*
|
|
1363
|
+
* // 设置语言
|
|
1364
|
+
* Locale.setLocale('zh-CN');
|
|
1365
|
+
*
|
|
1366
|
+
* // 获取当前语言
|
|
1367
|
+
* console.log(Locale.getLocale()); // 'zh-CN'
|
|
1368
|
+
*
|
|
1369
|
+
* // 添加自定义语言包
|
|
1370
|
+
* Locale.addLocale('ja-JP', {
|
|
1371
|
+
* required: '必須項目です',
|
|
1372
|
+
* min: '{{#limit}}文字以上必要です'
|
|
1373
|
+
* });
|
|
1374
|
+
*
|
|
1375
|
+
* // 获取可用语言列表
|
|
1376
|
+
* console.log(Locale.getAvailableLocales()); // ['zh-CN', 'en-US', 'ja-JP', ...]
|
|
1377
|
+
* ```
|
|
1378
|
+
*/
|
|
1379
|
+
export class Locale {
|
|
1380
|
+
/**
|
|
1381
|
+
* 设置当前语言
|
|
1382
|
+
* @param lang - 语言代码
|
|
1383
|
+
*/
|
|
1384
|
+
static setLocale(lang: 'en-US' | 'zh-CN' | 'ja-JP' | 'fr-FR' | 'es-ES' | string): void;
|
|
1385
|
+
|
|
1386
|
+
/**
|
|
1387
|
+
* 获取当前语言
|
|
1388
|
+
* @returns 语言代码
|
|
1389
|
+
*/
|
|
1390
|
+
static getLocale(): string;
|
|
1391
|
+
|
|
1392
|
+
/**
|
|
1393
|
+
* 添加语言包
|
|
1394
|
+
* @param locale - 语言代码
|
|
1395
|
+
* @param messages - 错误消息
|
|
1396
|
+
*/
|
|
1397
|
+
static addLocale(locale: string, messages: ErrorMessages): void;
|
|
1398
|
+
|
|
1399
|
+
/**
|
|
1400
|
+
* 设置当前语言包的消息
|
|
1401
|
+
* @param messages - 错误消息
|
|
1402
|
+
*/
|
|
1403
|
+
static setMessages(messages: ErrorMessages): void;
|
|
1404
|
+
|
|
1405
|
+
/**
|
|
1406
|
+
* 获取错误消息
|
|
1407
|
+
* @param type - 错误类型
|
|
1408
|
+
* @param customMessages - 自定义消息(可选)
|
|
1409
|
+
* @returns 错误消息字符串
|
|
1410
|
+
*/
|
|
1411
|
+
static getMessage(type: string, customMessages?: ErrorMessages): string;
|
|
1412
|
+
|
|
1413
|
+
/**
|
|
1414
|
+
* 获取可用的语言列表
|
|
1415
|
+
* @returns 语言代码数组
|
|
1416
|
+
*/
|
|
1417
|
+
static getAvailableLocales(): string[];
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
// ========== JSONSchemaCore 类 ==========
|
|
1421
|
+
|
|
1422
|
+
/**
|
|
1423
|
+
* JSON Schema 核心类
|
|
1424
|
+
*
|
|
1425
|
+
* @description 对 JSON Schema 进行封装,提供验证和操作方法
|
|
1426
|
+
*
|
|
1427
|
+
* @example
|
|
1428
|
+
* ```typescript
|
|
1429
|
+
* const core = new JSONSchemaCore({
|
|
1430
|
+
* type: 'string',
|
|
1431
|
+
* minLength: 3,
|
|
1432
|
+
* maxLength: 32
|
|
1433
|
+
* });
|
|
1434
|
+
*
|
|
1435
|
+
* const result = core.validate('test');
|
|
1436
|
+
* console.log(result.valid); // true
|
|
1437
|
+
* ```
|
|
1438
|
+
*/
|
|
1439
|
+
export class JSONSchemaCore {
|
|
1440
|
+
/**
|
|
1441
|
+
* 构造函数
|
|
1442
|
+
* @param schema - JSON Schema 对象
|
|
1443
|
+
*/
|
|
1444
|
+
constructor(schema: JSONSchema);
|
|
1445
|
+
|
|
1446
|
+
/**
|
|
1447
|
+
* 验证数据
|
|
1448
|
+
* @param data - 要验证的数据
|
|
1449
|
+
* @returns 验证结果
|
|
1450
|
+
*/
|
|
1451
|
+
validate<T = any>(data: any): ValidationResult<T>;
|
|
1452
|
+
|
|
1453
|
+
/**
|
|
1454
|
+
* 获取 JSON Schema 对象
|
|
1455
|
+
* @returns JSON Schema
|
|
1456
|
+
*/
|
|
1457
|
+
toJsonSchema(): JSONSchema;
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
// ========== ErrorFormatter 类 ==========
|
|
1461
|
+
|
|
1462
|
+
/**
|
|
1463
|
+
* 错误格式化器
|
|
1464
|
+
*
|
|
1465
|
+
* @description 格式化 ajv 验证错误为友好的错误消息
|
|
1466
|
+
*
|
|
1467
|
+
* @example
|
|
1468
|
+
* ```typescript
|
|
1469
|
+
* const formatter = new ErrorFormatter();
|
|
1470
|
+
* const errors = formatter.format(ajvErrors, { locale: 'zh-CN' });
|
|
1471
|
+
* ```
|
|
1472
|
+
*/
|
|
1473
|
+
export class ErrorFormatter {
|
|
1474
|
+
/**
|
|
1475
|
+
* 格式化错误
|
|
1476
|
+
* @param errors - ajv 错误数组
|
|
1477
|
+
* @param options - 格式化选项
|
|
1478
|
+
* @returns 格式化后的错误数组
|
|
1479
|
+
*/
|
|
1480
|
+
format(errors: any[], options?: { locale?: string }): ValidationError[];
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
// ========== MessageTemplate 类 ==========
|
|
1484
|
+
|
|
1485
|
+
/**
|
|
1486
|
+
* 消息模板类
|
|
1487
|
+
*
|
|
1488
|
+
* @description 处理错误消息模板和变量替换
|
|
1489
|
+
*
|
|
1490
|
+
* @example
|
|
1491
|
+
* ```typescript
|
|
1492
|
+
* const template = new MessageTemplate('至少需要{{#limit}}个字符');
|
|
1493
|
+
* const message = template.render({ limit: 3 });
|
|
1494
|
+
* console.log(message); // "至少需要3个字符"
|
|
1495
|
+
* ```
|
|
1496
|
+
*/
|
|
1497
|
+
export class MessageTemplate {
|
|
1498
|
+
/**
|
|
1499
|
+
* 构造函数
|
|
1500
|
+
* @param template - 消息模板字符串
|
|
1501
|
+
*/
|
|
1502
|
+
constructor(template: string);
|
|
1503
|
+
|
|
1504
|
+
/**
|
|
1505
|
+
* 渲染模板
|
|
1506
|
+
* @param variables - 模板变量
|
|
1507
|
+
* @returns 渲染后的消息
|
|
1508
|
+
*/
|
|
1509
|
+
render(variables: Record<string, any>): string;
|
|
1510
|
+
|
|
1511
|
+
/**
|
|
1512
|
+
* 静态渲染方法
|
|
1513
|
+
* @param template - 消息模板
|
|
1514
|
+
* @param variables - 模板变量
|
|
1515
|
+
* @returns 渲染后的消息
|
|
1516
|
+
*/
|
|
1517
|
+
static render(template: string, variables: Record<string, any>): string;
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
// ========== CacheManager 类 ==========
|
|
1521
|
+
|
|
1522
|
+
/**
|
|
1523
|
+
* 缓存管理器选项
|
|
1524
|
+
*/
|
|
1525
|
+
export interface CacheManagerOptions {
|
|
1526
|
+
/** 最大缓存条目数 */
|
|
1527
|
+
maxSize?: number;
|
|
1528
|
+
/** 缓存过期时间(毫秒) */
|
|
1529
|
+
ttl?: number;
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
/**
|
|
1533
|
+
* 缓存管理器
|
|
1534
|
+
*
|
|
1535
|
+
* @description LRU 缓存管理器,用于缓存编译后的 Schema
|
|
1536
|
+
*
|
|
1537
|
+
* @example
|
|
1538
|
+
* ```typescript
|
|
1539
|
+
* const cache = new CacheManager({ maxSize: 1000, ttl: 60000 });
|
|
1540
|
+
*
|
|
1541
|
+
* // 设置缓存
|
|
1542
|
+
* cache.set('key', value);
|
|
1543
|
+
*
|
|
1544
|
+
* // 获取缓存
|
|
1545
|
+
* const value = cache.get('key');
|
|
1546
|
+
*
|
|
1547
|
+
* // 清空缓存
|
|
1548
|
+
* cache.clear();
|
|
1549
|
+
* ```
|
|
1550
|
+
*/
|
|
1551
|
+
export class CacheManager {
|
|
1552
|
+
/**
|
|
1553
|
+
* 构造函数
|
|
1554
|
+
* @param options - 缓存选项
|
|
1555
|
+
*/
|
|
1556
|
+
constructor(options?: CacheManagerOptions);
|
|
1557
|
+
|
|
1558
|
+
/**
|
|
1559
|
+
* 缓存选项
|
|
1560
|
+
*/
|
|
1561
|
+
options: CacheManagerOptions;
|
|
1562
|
+
|
|
1563
|
+
/**
|
|
1564
|
+
* 设置缓存
|
|
1565
|
+
* @param key - 缓存键
|
|
1566
|
+
* @param value - 缓存值
|
|
1567
|
+
*/
|
|
1568
|
+
set(key: string, value: any): void;
|
|
1569
|
+
|
|
1570
|
+
/**
|
|
1571
|
+
* 获取缓存
|
|
1572
|
+
* @param key - 缓存键
|
|
1573
|
+
* @returns 缓存值或 undefined
|
|
1574
|
+
*/
|
|
1575
|
+
get(key: string): any | undefined;
|
|
1576
|
+
|
|
1577
|
+
/**
|
|
1578
|
+
* 检查缓存是否存在
|
|
1579
|
+
* @param key - 缓存键
|
|
1580
|
+
* @returns 是否存在
|
|
1581
|
+
*/
|
|
1582
|
+
has(key: string): boolean;
|
|
1583
|
+
|
|
1584
|
+
/**
|
|
1585
|
+
* 删除缓存
|
|
1586
|
+
* @param key - 缓存键
|
|
1587
|
+
*/
|
|
1588
|
+
delete(key: string): void;
|
|
1589
|
+
|
|
1590
|
+
/**
|
|
1591
|
+
* 清空所有缓存
|
|
1592
|
+
*/
|
|
1593
|
+
clear(): void;
|
|
1594
|
+
|
|
1595
|
+
/**
|
|
1596
|
+
* 获取缓存统计信息
|
|
1597
|
+
* @returns 统计信息对象
|
|
1598
|
+
*/
|
|
1599
|
+
getStats(): {
|
|
1600
|
+
size: number;
|
|
1601
|
+
hits: number;
|
|
1602
|
+
misses: number;
|
|
1603
|
+
evictions: number;
|
|
1604
|
+
};
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
// ========== PluginManager 类 ==========
|
|
1608
|
+
|
|
1609
|
+
/**
|
|
1610
|
+
* 插件接口
|
|
1611
|
+
*/
|
|
1612
|
+
export interface Plugin {
|
|
1613
|
+
/** 插件名称 */
|
|
1614
|
+
name: string;
|
|
1615
|
+
/** 插件版本 */
|
|
1616
|
+
version: string;
|
|
1617
|
+
/** 插件描述 */
|
|
1618
|
+
description?: string;
|
|
1619
|
+
/** 安装方法 */
|
|
1620
|
+
install(core: any, options?: any, context?: any): void;
|
|
1621
|
+
/** 卸载方法(可选) */
|
|
1622
|
+
uninstall?(core: any, context?: any): void;
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
/**
|
|
1626
|
+
* 插件管理器
|
|
1627
|
+
*
|
|
1628
|
+
* @description 管理验证库的插件系统
|
|
1629
|
+
*
|
|
1630
|
+
* @example
|
|
1631
|
+
* ```typescript
|
|
1632
|
+
* const pluginManager = new PluginManager();
|
|
1633
|
+
*
|
|
1634
|
+
* // 注册插件
|
|
1635
|
+
* pluginManager.register({
|
|
1636
|
+
* name: 'my-plugin',
|
|
1637
|
+
* version: '1.0.0',
|
|
1638
|
+
* install(core) {
|
|
1639
|
+
* // 安装逻辑
|
|
1640
|
+
* }
|
|
1641
|
+
* });
|
|
1642
|
+
*
|
|
1643
|
+
* // 安装插件
|
|
1644
|
+
* pluginManager.install(schemaCore);
|
|
1645
|
+
*
|
|
1646
|
+
* // 获取插件
|
|
1647
|
+
* const plugin = pluginManager.get('my-plugin');
|
|
1648
|
+
* ```
|
|
1649
|
+
*/
|
|
1650
|
+
export class PluginManager {
|
|
1651
|
+
/**
|
|
1652
|
+
* 构造函数
|
|
1653
|
+
*/
|
|
1654
|
+
constructor();
|
|
1655
|
+
|
|
1656
|
+
/**
|
|
1657
|
+
* 注册插件
|
|
1658
|
+
* @param plugin - 插件对象
|
|
1659
|
+
*/
|
|
1660
|
+
register(plugin: Plugin): void;
|
|
1661
|
+
|
|
1662
|
+
/**
|
|
1663
|
+
* 安装所有插件
|
|
1664
|
+
* @param core - 核心对象
|
|
1665
|
+
* @param options - 安装选项
|
|
1666
|
+
*/
|
|
1667
|
+
install(core: any, options?: any): void;
|
|
1668
|
+
|
|
1669
|
+
/**
|
|
1670
|
+
* 获取插件
|
|
1671
|
+
* @param name - 插件名称
|
|
1672
|
+
* @returns 插件对象或 undefined
|
|
1673
|
+
*/
|
|
1674
|
+
get(name: string): Plugin | undefined;
|
|
1675
|
+
|
|
1676
|
+
/**
|
|
1677
|
+
* 卸载插件
|
|
1678
|
+
* @param name - 插件名称
|
|
1679
|
+
*/
|
|
1680
|
+
uninstall(name: string): void;
|
|
1681
|
+
|
|
1682
|
+
/**
|
|
1683
|
+
* 列出所有插件
|
|
1684
|
+
* @returns 插件名称数组
|
|
1685
|
+
*/
|
|
1686
|
+
list(): string[];
|
|
1687
|
+
|
|
1688
|
+
/**
|
|
1689
|
+
* 清空所有插件
|
|
1690
|
+
*/
|
|
1691
|
+
clear(): void;
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
// ========== MarkdownExporter 类 ==========
|
|
1695
|
+
|
|
1696
|
+
/**
|
|
1697
|
+
* Markdown 导出器选项
|
|
1698
|
+
*/
|
|
1699
|
+
export interface MarkdownExporterOptions {
|
|
1700
|
+
/** 文档标题 */
|
|
1701
|
+
title?: string;
|
|
1702
|
+
/** 语言(zh-CN, en-US等) */
|
|
1703
|
+
locale?: string;
|
|
1704
|
+
/** 是否包含示例数据 */
|
|
1705
|
+
includeExamples?: boolean;
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
/**
|
|
1709
|
+
* Markdown 导出器
|
|
1710
|
+
*
|
|
1711
|
+
* @description 将 JSON Schema 导出为 Markdown 文档
|
|
1712
|
+
*
|
|
1713
|
+
* @example
|
|
1714
|
+
* ```typescript
|
|
1715
|
+
* const exporter = new MarkdownExporter();
|
|
1716
|
+
* const markdown = exporter.export(schema, {
|
|
1717
|
+
* title: '用户注册 API',
|
|
1718
|
+
* locale: 'zh-CN',
|
|
1719
|
+
* includeExamples: true
|
|
1720
|
+
* });
|
|
1721
|
+
*
|
|
1722
|
+
* console.log(markdown);
|
|
1723
|
+
* // # 用户注册 API
|
|
1724
|
+
* //
|
|
1725
|
+
* // ## 字段列表
|
|
1726
|
+
* // | 字段名 | 类型 | 必填 | 约束 | 说明 |
|
|
1727
|
+
* // |--------|------|------|------|------|
|
|
1728
|
+
* // | username | 字符串 | ✅ | 长度: 3-32 | - |
|
|
1729
|
+
* ```
|
|
1730
|
+
*/
|
|
1731
|
+
export class MarkdownExporter {
|
|
1732
|
+
/**
|
|
1733
|
+
* 构造函数
|
|
1734
|
+
*/
|
|
1735
|
+
constructor();
|
|
1736
|
+
|
|
1737
|
+
/**
|
|
1738
|
+
* 导出为 Markdown
|
|
1739
|
+
* @param schema - JSON Schema 对象
|
|
1740
|
+
* @param options - 导出选项
|
|
1741
|
+
* @returns Markdown 字符串
|
|
1742
|
+
*/
|
|
1743
|
+
export(schema: JSONSchema, options?: MarkdownExporterOptions): string;
|
|
1744
|
+
|
|
1745
|
+
/**
|
|
1746
|
+
* 静态导出方法
|
|
1747
|
+
* @param schema - JSON Schema 对象
|
|
1748
|
+
* @param options - 导出选项
|
|
1749
|
+
* @returns Markdown 字符串
|
|
1750
|
+
*/
|
|
1751
|
+
static export(schema: JSONSchema, options?: MarkdownExporterOptions): string;
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
// ========== CustomKeywords 类 ==========
|
|
1755
|
+
|
|
1756
|
+
/**
|
|
1757
|
+
* 自定义关键字
|
|
1758
|
+
*
|
|
1759
|
+
* @description 扩展 ajv 的自定义验证关键字
|
|
1760
|
+
*
|
|
1761
|
+
* @example
|
|
1762
|
+
* ```typescript
|
|
1763
|
+
* // 添加自定义关键字通常通过 Validator 的 addKeyword 方法
|
|
1764
|
+
* const validator = new Validator();
|
|
1765
|
+
* const ajv = validator.getAjv();
|
|
1766
|
+
*
|
|
1767
|
+
* // 使用 ajv.addKeyword() 添加自定义关键字
|
|
1768
|
+
* ```
|
|
1769
|
+
*/
|
|
1770
|
+
export const CustomKeywords: any;
|
|
1771
|
+
|
|
1772
|
+
// ========== dsl.config 选项(v2.3.0+)==========
|
|
1773
|
+
|
|
1774
|
+
/**
|
|
1775
|
+
* i18n 配置选项(v2.3.0+)
|
|
1776
|
+
*/
|
|
1777
|
+
export interface I18nConfig {
|
|
1778
|
+
/** 语言包目录路径 */
|
|
1779
|
+
localesPath?: string;
|
|
1780
|
+
/** 直接传入的语言包 */
|
|
1781
|
+
locales?: Record<string, ErrorMessages>;
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
/**
|
|
1785
|
+
* 缓存配置选项(v2.3.0+)
|
|
1786
|
+
*/
|
|
1787
|
+
export interface CacheConfig {
|
|
1788
|
+
/** 最大缓存条目数 */
|
|
1789
|
+
maxSize?: number;
|
|
1790
|
+
/** 缓存过期时间(毫秒) */
|
|
1791
|
+
ttl?: number;
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
/**
|
|
1795
|
+
* dsl.config() 配置选项(v2.3.0+)
|
|
1796
|
+
*
|
|
1797
|
+
* @description 全局配置选项,包括多语言和缓存设置
|
|
1798
|
+
*
|
|
1799
|
+
* @example
|
|
1800
|
+
* ```typescript
|
|
1801
|
+
* // 配置多语言
|
|
1802
|
+
* dsl.config({
|
|
1803
|
+
* i18n: {
|
|
1804
|
+
* locales: {
|
|
1805
|
+
* 'zh-CN': { 'username': '用户名' },
|
|
1806
|
+
* 'en-US': { 'username': 'Username' }
|
|
1807
|
+
* }
|
|
1808
|
+
* }
|
|
1809
|
+
* });
|
|
1810
|
+
*
|
|
1811
|
+
* // 配置缓存
|
|
1812
|
+
* dsl.config({
|
|
1813
|
+
* cache: {
|
|
1814
|
+
* maxSize: 5000,
|
|
1815
|
+
* ttl: 60000
|
|
1816
|
+
* }
|
|
1817
|
+
* });
|
|
1818
|
+
*
|
|
1819
|
+
* // 同时配置多个选项
|
|
1820
|
+
* dsl.config({
|
|
1821
|
+
* i18n: { locales: {...} },
|
|
1822
|
+
* cache: { maxSize: 5000 },
|
|
1823
|
+
* patterns: {
|
|
1824
|
+
* phone: { cn: /^1[3-9]\d{9}$/ }
|
|
1825
|
+
* }
|
|
1826
|
+
* });
|
|
1827
|
+
* ```
|
|
1828
|
+
*/
|
|
1829
|
+
export interface DslConfigOptions {
|
|
1830
|
+
/** i18n 配置 */
|
|
1831
|
+
i18n?: I18nConfig;
|
|
1832
|
+
/** 缓存配置 */
|
|
1833
|
+
cache?: CacheConfig;
|
|
1834
|
+
/** 自定义验证规则扩展 */
|
|
1835
|
+
patterns?: {
|
|
1836
|
+
/** 手机号验证规则 */
|
|
1837
|
+
phone?: Record<string, RegExp>;
|
|
1838
|
+
/** 身份证验证规则 */
|
|
1839
|
+
idCard?: Record<string, RegExp>;
|
|
1840
|
+
/** 信用卡验证规则 */
|
|
1841
|
+
creditCard?: Record<string, RegExp>;
|
|
1842
|
+
};
|
|
1843
|
+
/** 向后兼容:手机号验证规则(推荐使用 patterns.phone) */
|
|
1844
|
+
phone?: Record<string, RegExp>;
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
// ========== exporters 对象 ==========
|
|
1848
|
+
|
|
1849
|
+
/**
|
|
1850
|
+
* 导出器集合
|
|
1851
|
+
*
|
|
1852
|
+
* @description 包含所有导出器的对象
|
|
1853
|
+
*
|
|
1854
|
+
* @example
|
|
1855
|
+
* ```typescript
|
|
1856
|
+
* import { exporters } from 'schema-dsl';
|
|
1857
|
+
*
|
|
1858
|
+
* // 使用 MongoDB 导出器
|
|
1859
|
+
* const mongoSchema = exporters.MongoDBExporter.export(schema);
|
|
1860
|
+
*
|
|
1861
|
+
* // 使用 MySQL 导出器
|
|
1862
|
+
* const mysqlDDL = new exporters.MySQLExporter().export(schema, { tableName: 'users' });
|
|
1863
|
+
* ```
|
|
1864
|
+
*/
|
|
1865
|
+
export const exporters: {
|
|
1866
|
+
MongoDBExporter: typeof MongoDBExporter;
|
|
1867
|
+
MySQLExporter: typeof MySQLExporter;
|
|
1868
|
+
PostgreSQLExporter: typeof PostgreSQLExporter;
|
|
1869
|
+
MarkdownExporter: typeof MarkdownExporter;
|
|
1870
|
+
};
|
|
1871
|
+
|
|
1872
|
+
// ========== String 扩展控制 ==========
|
|
1873
|
+
|
|
1874
|
+
/**
|
|
1875
|
+
* 安装 String 扩展
|
|
1876
|
+
*
|
|
1877
|
+
* @description 将DSL方法添加到String.prototype,使字符串支持链式调用
|
|
1878
|
+
*
|
|
1879
|
+
* @example
|
|
1880
|
+
* ```typescript
|
|
1881
|
+
* import { installStringExtensions } from 'schema-dsl';
|
|
1882
|
+
*
|
|
1883
|
+
* // 安装扩展
|
|
1884
|
+
* installStringExtensions();
|
|
1885
|
+
*
|
|
1886
|
+
* // 现在可以在字符串上使用DSL方法
|
|
1887
|
+
* const schema = dsl({
|
|
1888
|
+
* email: 'email!'.label('邮箱地址').messages({ required: '必填' })
|
|
1889
|
+
* });
|
|
1890
|
+
* ```
|
|
1891
|
+
*/
|
|
1892
|
+
export function installStringExtensions(): void;
|
|
1893
|
+
|
|
1894
|
+
/**
|
|
1895
|
+
* 卸载 String 扩展
|
|
1896
|
+
*
|
|
1897
|
+
* @description 从String.prototype移除DSL方法
|
|
1898
|
+
*
|
|
1899
|
+
* @example
|
|
1900
|
+
* ```typescript
|
|
1901
|
+
* import { uninstallStringExtensions } from 'schema-dsl';
|
|
1902
|
+
*
|
|
1903
|
+
* // 卸载扩展
|
|
1904
|
+
* uninstallStringExtensions();
|
|
1905
|
+
*
|
|
1906
|
+
* // 字符串不再支持DSL方法
|
|
1907
|
+
* ```
|
|
1908
|
+
*/
|
|
1909
|
+
export function uninstallStringExtensions(): void;
|
|
1910
|
+
|
|
1911
|
+
// ========== Express/Koa 中间件 ==========
|
|
1912
|
+
|
|
1913
|
+
/**
|
|
1914
|
+
* Express/Koa中间件选项
|
|
1915
|
+
*
|
|
1916
|
+
* @description 验证中间件的配置选项
|
|
1917
|
+
*/
|
|
1918
|
+
export interface MiddlewareOptions {
|
|
1919
|
+
/** 验证请求体 */
|
|
1920
|
+
body?: SchemaIO | JSONSchema;
|
|
1921
|
+
/** 验证URL查询参数 */
|
|
1922
|
+
query?: SchemaIO | JSONSchema;
|
|
1923
|
+
/** 验证URL路径参数 */
|
|
1924
|
+
params?: SchemaIO | JSONSchema;
|
|
1925
|
+
/** 验证请求头 */
|
|
1926
|
+
headers?: SchemaIO | JSONSchema;
|
|
1927
|
+
/** 错误处理函数 */
|
|
1928
|
+
onError?: (errors: ValidationError[], req: any, res: any, next: any) => void;
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
/**
|
|
1932
|
+
* Express/Koa验证中间件
|
|
1933
|
+
*
|
|
1934
|
+
* @description 创建验证中间件,自动验证请求数据
|
|
1935
|
+
*
|
|
1936
|
+
* @example
|
|
1937
|
+
* ```typescript
|
|
1938
|
+
* import express from 'express';
|
|
1939
|
+
* import schema-dsl from 'schema-dsl';
|
|
1940
|
+
*
|
|
1941
|
+
* const app = express();
|
|
1942
|
+
* app.use(express.json());
|
|
1943
|
+
*
|
|
1944
|
+
* // 定义Schema
|
|
1945
|
+
* const userSchema = schema-dsl({
|
|
1946
|
+
* username: 'string:3-32!',
|
|
1947
|
+
* email: 'email!',
|
|
1948
|
+
* age: 'number:18-100'
|
|
1949
|
+
* });
|
|
1950
|
+
*
|
|
1951
|
+
* // 使用中间件
|
|
1952
|
+
* app.post('/api/user',
|
|
1953
|
+
* schema-dsl.middleware({ body: userSchema }),
|
|
1954
|
+
* (req, res) => {
|
|
1955
|
+
* // req.body 已经通过验证
|
|
1956
|
+
* res.json({ success: true, data: req.body });
|
|
1957
|
+
* }
|
|
1958
|
+
* );
|
|
1959
|
+
*
|
|
1960
|
+
* // 自定义错误处理
|
|
1961
|
+
* app.post('/api/user2',
|
|
1962
|
+
* schema-dsl.middleware({
|
|
1963
|
+
* body: userSchema,
|
|
1964
|
+
* onError: (errors, req, res, next) => {
|
|
1965
|
+
* res.status(400).json({
|
|
1966
|
+
* success: false,
|
|
1967
|
+
* errors: errors.map(e => ({
|
|
1968
|
+
* field: e.field,
|
|
1969
|
+
* message: e.message
|
|
1970
|
+
* }))
|
|
1971
|
+
* });
|
|
1972
|
+
* }
|
|
1973
|
+
* }),
|
|
1974
|
+
* (req, res) => {
|
|
1975
|
+
* res.json({ success: true });
|
|
1976
|
+
* }
|
|
1977
|
+
* );
|
|
1978
|
+
* ```
|
|
1979
|
+
*/
|
|
1980
|
+
export function middleware(options: MiddlewareOptions): (req: any, res: any, next: any) => void;
|
|
1981
|
+
|
|
1982
|
+
// ========== 默认导出 ==========
|
|
1983
|
+
|
|
1984
|
+
/**
|
|
1985
|
+
* 默认导出(dsl函数)
|
|
1986
|
+
*
|
|
1987
|
+
* @example
|
|
1988
|
+
* ```typescript
|
|
1989
|
+
* import schema-dsl from 'schema-dsl';
|
|
1990
|
+
*
|
|
1991
|
+
* const schema = schema-dsl({
|
|
1992
|
+
* username: 'string:3-32!',
|
|
1993
|
+
* email: 'email!'
|
|
1994
|
+
* });
|
|
1995
|
+
* ```
|
|
1996
|
+
*/
|
|
1997
|
+
export default dsl;
|
|
1998
|
+
}
|
|
1999
|
+
|