schema-dsl 1.0.0 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +263 -529
  2. package/README.md +814 -896
  3. package/STATUS.md +135 -2
  4. package/docs/INDEX.md +1 -2
  5. package/docs/api-reference.md +1 -292
  6. package/docs/custom-extensions-guide.md +411 -0
  7. package/docs/enum.md +475 -0
  8. package/docs/i18n.md +394 -0
  9. package/docs/performance-benchmark-report.md +179 -0
  10. package/docs/plugin-system.md +8 -8
  11. package/docs/typescript-guide.md +554 -0
  12. package/docs/validate-async.md +1 -1
  13. package/docs/validation-rules-v1.0.2.md +1601 -0
  14. package/examples/README.md +81 -0
  15. package/examples/enum.examples.js +324 -0
  16. package/examples/express-integration.js +54 -54
  17. package/examples/i18n-full-demo.js +15 -24
  18. package/examples/schema-utils-chaining.examples.js +2 -2
  19. package/examples/slug.examples.js +179 -0
  20. package/index.d.ts +246 -17
  21. package/index.js +30 -34
  22. package/lib/config/constants.js +1 -1
  23. package/lib/config/patterns/common.js +47 -0
  24. package/lib/config/patterns/index.js +2 -1
  25. package/lib/core/DslBuilder.js +500 -8
  26. package/lib/core/StringExtensions.js +31 -0
  27. package/lib/core/Validator.js +42 -15
  28. package/lib/errors/ValidationError.js +3 -3
  29. package/lib/locales/en-US.js +79 -19
  30. package/lib/locales/es-ES.js +60 -19
  31. package/lib/locales/fr-FR.js +84 -43
  32. package/lib/locales/ja-JP.js +83 -42
  33. package/lib/locales/zh-CN.js +32 -0
  34. package/lib/validators/CustomKeywords.js +405 -0
  35. package/package.json +1 -1
  36. package/.github/CODE_OF_CONDUCT.md +0 -45
  37. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -57
  38. package/.github/ISSUE_TEMPLATE/config.yml +0 -11
  39. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -45
  40. package/.github/ISSUE_TEMPLATE/question.md +0 -31
  41. package/.github/PULL_REQUEST_TEMPLATE.md +0 -70
  42. package/.github/SECURITY.md +0 -184
  43. package/.github/workflows/ci.yml +0 -33
  44. package/plugins/custom-format.js +0 -101
  45. package/plugins/custom-validator.js +0 -200
@@ -0,0 +1,554 @@
1
+ # TypeScript 使用指南
2
+
3
+ > **版本**: schema-dsl v1.0.3+
4
+ > **更新日期**: 2025-12-31
5
+
6
+ ---
7
+
8
+ ## 📋 目录
9
+
10
+ 1. [快速开始](#1-快速开始)
11
+ 2. [TypeScript 中的链式调用](#2-typescript-中的链式调用)
12
+ 3. [类型推导最佳实践](#3-类型推导最佳实践)
13
+ 4. [完整示例](#4-完整示例)
14
+ 5. [常见问题](#5-常见问题)
15
+
16
+ ---
17
+
18
+ ## 1. 快速开始
19
+
20
+ ### 1.1 安装
21
+
22
+ ```bash
23
+ npm install schema-dsl
24
+ ```
25
+
26
+ ### 1.2 基础用法
27
+
28
+ ```typescript
29
+ import { dsl, validate } from 'schema-dsl';
30
+
31
+ // 定义 Schema
32
+ const userSchema = dsl({
33
+ username: 'string:3-32!',
34
+ email: 'email!',
35
+ age: 'number:18-100'
36
+ });
37
+
38
+ // 验证数据
39
+ const result = validate(userSchema, {
40
+ username: 'testuser',
41
+ email: 'test@example.com',
42
+ age: 25
43
+ });
44
+
45
+ if (result.valid) {
46
+ console.log('验证通过:', result.data);
47
+ } else {
48
+ console.log('验证失败:', result.errors);
49
+ }
50
+ ```
51
+
52
+ ---
53
+
54
+ ## 2. TypeScript 中的链式调用
55
+
56
+ ### 2.1 问题说明
57
+
58
+ 由于 TypeScript 对全局 `String.prototype` 扩展的类型推导限制,在 `.ts` 文件中直接使用字符串链式调用可能会缺少类型提示:
59
+
60
+ ```typescript
61
+ // ❌ TypeScript 可能无法正确推导类型
62
+ const schema = dsl({
63
+ email: 'email!'.label('邮箱') // 可能报错或无类型提示
64
+ });
65
+ ```
66
+
67
+ ### 2.2 推荐解决方案 ⭐
68
+
69
+ **使用 `dsl()` 函数包裹字符串**,可以获得完整的类型推导和 IDE 提示:
70
+
71
+ ```typescript
72
+ // ✅ 推荐:使用 dsl() 包裹
73
+ const schema = dsl({
74
+ email: dsl('email!').label('邮箱').pattern(/custom/)
75
+ });
76
+ ```
77
+
78
+ ### 2.3 工作原理
79
+
80
+ ```typescript
81
+ // dsl(string) 返回 DslBuilder 实例
82
+ const emailBuilder = dsl('email!');
83
+ // ^? DslBuilder - 完整的类型定义
84
+
85
+ // DslBuilder 支持所有链式方法,并有完整类型提示
86
+ emailBuilder.label('邮箱')
87
+ // ^? IDE 自动提示所有可用方法
88
+ .pattern(/^[a-z]+@[a-z]+\.[a-z]+$/)
89
+ .messages({ required: '邮箱必填' });
90
+ ```
91
+
92
+ ---
93
+
94
+ ## 3. 类型推导最佳实践
95
+
96
+ ### 3.1 方式对比
97
+
98
+ | 方式 | JavaScript | TypeScript | 类型推导 | 推荐度 |
99
+ |------|-----------|-----------|---------|--------|
100
+ | 直接字符串 | ✅ 完美 | ⚠️ 可能无提示 | ❌ 弱 | ⭐⭐ |
101
+ | dsl() 包裹 | ✅ 完美 | ✅ 完美 | ✅ 强 | ⭐⭐⭐⭐⭐ |
102
+ | 先定义再使用 | ✅ 完美 | ✅ 完美 | ✅ 强 | ⭐⭐⭐⭐ |
103
+
104
+ ### 3.2 推荐写法
105
+
106
+ #### ✅ 方式 1: 内联使用 dsl() 包裹(最推荐)
107
+
108
+ ```typescript
109
+ const schema = dsl({
110
+ username: dsl('string:3-32!')
111
+ .pattern(/^[a-zA-Z0-9_]+$/, '只能包含字母、数字和下划线')
112
+ .label('用户名'),
113
+
114
+ email: dsl('email!')
115
+ .label('邮箱地址')
116
+ .messages({ required: '邮箱必填' }),
117
+
118
+ age: dsl('number:18-100')
119
+ .label('年龄')
120
+ });
121
+ ```
122
+
123
+ **优点**:
124
+ - ✅ 完整的类型推导
125
+ - ✅ IDE 自动提示所有方法
126
+ - ✅ 代码紧凑,逻辑清晰
127
+
128
+ #### ✅ 方式 2: 先定义字段,再组合(适合复用)
129
+
130
+ ```typescript
131
+ // 定义可复用的字段
132
+ const emailField = dsl('email!')
133
+ .label('邮箱地址')
134
+ .messages({ required: '邮箱必填' });
135
+
136
+ const usernameField = dsl('string:3-32!')
137
+ .pattern(/^[a-zA-Z0-9_]+$/)
138
+ .label('用户名');
139
+
140
+ // 组合使用
141
+ const registrationSchema = dsl({
142
+ email: emailField,
143
+ username: usernameField,
144
+ password: dsl('string:8-64!').password('strong')
145
+ });
146
+
147
+ const loginSchema = dsl({
148
+ email: emailField, // 复用
149
+ password: dsl('string!').label('密码')
150
+ });
151
+ ```
152
+
153
+ **优点**:
154
+ - ✅ 字段定义可复用
155
+ - ✅ 代码更模块化
156
+ - ✅ 适合大型项目
157
+
158
+ #### ❌ 不推荐的写法
159
+
160
+ ```typescript
161
+ // ❌ 在 TypeScript 中直接使用字符串链式调用
162
+ const schema = dsl({
163
+ email: 'email!'.label('邮箱') // 可能无类型提示
164
+ });
165
+
166
+ // ❌ 混合使用(不一致)
167
+ const schema = dsl({
168
+ email: 'email!'.label('邮箱'), // 字符串扩展
169
+ username: dsl('string!').label('用户名') // dsl 包裹
170
+ });
171
+ ```
172
+
173
+ ---
174
+
175
+ ## 4. 完整示例
176
+
177
+ ### 4.1 用户注册表单
178
+
179
+ ```typescript
180
+ import { dsl, validateAsync, ValidationError } from 'schema-dsl';
181
+
182
+ // 定义 Schema
183
+ const registrationSchema = dsl({
184
+ profile: dsl({
185
+ username: dsl('string:3-32!')
186
+ .pattern(/^[a-zA-Z0-9_]+$/, '只能包含字母、数字和下划线')
187
+ .label('用户名')
188
+ .messages({
189
+ min: '用户名至少3个字符',
190
+ max: '用户名最多32个字符'
191
+ }),
192
+
193
+ email: dsl('email!')
194
+ .label('邮箱地址')
195
+ .messages({ required: '邮箱必填' }),
196
+
197
+ password: dsl('string!')
198
+ .password('strong')
199
+ .label('密码'),
200
+
201
+ age: dsl('number:18-100')
202
+ .label('年龄')
203
+ }),
204
+
205
+ settings: dsl({
206
+ emailNotify: dsl('boolean')
207
+ .default(true)
208
+ .label('邮件通知'),
209
+
210
+ language: dsl('string')
211
+ .default('zh-CN')
212
+ .label('语言设置')
213
+ })
214
+ });
215
+
216
+ // 异步验证(推荐)
217
+ async function registerUser(data: any) {
218
+ try {
219
+ const validData = await validateAsync(registrationSchema, data);
220
+ console.log('注册成功:', validData);
221
+ return validData;
222
+ } catch (error) {
223
+ if (error instanceof ValidationError) {
224
+ console.log('验证失败:');
225
+ error.errors.forEach(err => {
226
+ console.log(` - ${err.path}: ${err.message}`);
227
+ });
228
+ throw error;
229
+ }
230
+ throw error;
231
+ }
232
+ }
233
+
234
+ // 使用
235
+ registerUser({
236
+ profile: {
237
+ username: 'testuser',
238
+ email: 'test@example.com',
239
+ password: 'StrongPass123!',
240
+ age: 25
241
+ },
242
+ settings: {
243
+ emailNotify: true,
244
+ language: 'en-US'
245
+ }
246
+ });
247
+ ```
248
+
249
+ ### 4.2 API 请求验证
250
+
251
+ ```typescript
252
+ import { dsl, validateAsync } from 'schema-dsl';
253
+ import express from 'express';
254
+
255
+ const app = express();
256
+ app.use(express.json());
257
+
258
+ // 定义 API Schema
259
+ const createUserSchema = dsl({
260
+ username: dsl('string:3-32!')
261
+ .pattern(/^[a-zA-Z0-9_]+$/)
262
+ .label('用户名'),
263
+
264
+ email: dsl('email!').label('邮箱'),
265
+
266
+ role: dsl('string')
267
+ .default('user')
268
+ .label('角色')
269
+ });
270
+
271
+ // 使用中间件
272
+ app.post('/api/users', async (req, res) => {
273
+ try {
274
+ const validData = await validateAsync(createUserSchema, req.body);
275
+
276
+ // 创建用户逻辑
277
+ const user = await createUser(validData);
278
+
279
+ res.json({ success: true, data: user });
280
+ } catch (error) {
281
+ if (error instanceof ValidationError) {
282
+ res.status(400).json({
283
+ success: false,
284
+ errors: error.errors.map(e => ({
285
+ field: e.path,
286
+ message: e.message
287
+ }))
288
+ });
289
+ } else {
290
+ res.status(500).json({ success: false, message: '服务器错误' });
291
+ }
292
+ }
293
+ });
294
+ ```
295
+
296
+ ### 4.3 表单字段复用
297
+
298
+ ```typescript
299
+ import { dsl } from 'schema-dsl';
300
+
301
+ // 定义常用字段
302
+ const commonFields = {
303
+ email: dsl('email!')
304
+ .label('邮箱地址')
305
+ .messages({ required: '邮箱必填' }),
306
+
307
+ username: dsl('string:3-32!')
308
+ .pattern(/^[a-zA-Z0-9_]+$/)
309
+ .label('用户名'),
310
+
311
+ password: dsl('string!')
312
+ .password('strong')
313
+ .label('密码')
314
+ };
315
+
316
+ // 注册表单
317
+ const registrationSchema = dsl({
318
+ ...commonFields,
319
+ confirmPassword: dsl('string!')
320
+ .label('确认密码')
321
+ });
322
+
323
+ // 登录表单
324
+ const loginSchema = dsl({
325
+ email: commonFields.email,
326
+ password: dsl('string!').label('密码') // 登录时不需要强密码验证
327
+ });
328
+
329
+ // 密码重置表单
330
+ const resetPasswordSchema = dsl({
331
+ email: commonFields.email,
332
+ newPassword: commonFields.password,
333
+ confirmPassword: dsl('string!').label('确认新密码')
334
+ });
335
+ ```
336
+
337
+ ---
338
+
339
+ ## 5. 常见问题
340
+
341
+ ### 5.1 为什么 TypeScript 中字符串链式调用没有类型提示?
342
+
343
+ **原因**: TypeScript 对全局 `String.prototype` 扩展的类型推导有限制。
344
+
345
+ **解决**: 使用 `dsl()` 包裹字符串:
346
+
347
+ ```typescript
348
+ // ❌ 可能无提示
349
+ 'email!'.label('邮箱')
350
+
351
+ // ✅ 完整提示
352
+ dsl('email!').label('邮箱')
353
+ ```
354
+
355
+ ### 5.2 JavaScript 用户需要改变写法吗?
356
+
357
+ **不需要!** JavaScript 用户可以继续使用字符串链式调用:
358
+
359
+ ```javascript
360
+ // JavaScript 中完全正常
361
+ const schema = dsl({
362
+ email: 'email!'.label('邮箱')
363
+ });
364
+ ```
365
+
366
+ ### 5.3 如何在严格模式下使用?
367
+
368
+ 在 `tsconfig.json` 中启用严格模式也没问题:
369
+
370
+ ```json
371
+ {
372
+ "compilerOptions": {
373
+ "strict": true,
374
+ "noImplicitAny": true
375
+ }
376
+ }
377
+ ```
378
+
379
+ 只需使用 `dsl()` 包裹即可:
380
+
381
+ ```typescript
382
+ const schema = dsl({
383
+ email: dsl('email!').label('邮箱') // ✅ 严格模式下正常
384
+ });
385
+ ```
386
+
387
+ ### 5.4 如何获取验证后的数据类型?
388
+
389
+ 使用泛型参数:
390
+
391
+ ```typescript
392
+ interface User {
393
+ username: string;
394
+ email: string;
395
+ age?: number;
396
+ }
397
+
398
+ // 同步验证
399
+ const result = validate<User>(userSchema, data);
400
+ if (result.valid) {
401
+ const user: User = result.data; // ✅ 类型安全
402
+ }
403
+
404
+ // 异步验证
405
+ const validUser = await validateAsync<User>(userSchema, data);
406
+ // ^? User - 完整的类型推导
407
+ ```
408
+
409
+ ### 5.5 如何处理嵌套对象的验证错误?
410
+
411
+ ```typescript
412
+ try {
413
+ await validateAsync(schema, data);
414
+ } catch (error) {
415
+ if (error instanceof ValidationError) {
416
+ // 方式 1: 遍历所有错误
417
+ error.errors.forEach(err => {
418
+ console.log(`${err.path}: ${err.message}`);
419
+ // 输出: profile.username: 用户名至少3个字符
420
+ });
421
+
422
+ // 方式 2: 获取特定字段错误
423
+ const usernameError = error.getFieldError('profile.username');
424
+ if (usernameError) {
425
+ console.log(usernameError.message);
426
+ }
427
+
428
+ // 方式 3: 获取所有字段错误映射
429
+ const fieldErrors = error.getFieldErrors();
430
+ // { 'profile.username': {...}, 'profile.email': {...} }
431
+ }
432
+ }
433
+ ```
434
+
435
+ ---
436
+
437
+ ## 6. 进阶技巧
438
+
439
+ ### 6.1 自定义验证器
440
+
441
+ ```typescript
442
+ const schema = dsl({
443
+ username: dsl('string:3-32!')
444
+ .custom(async (value) => {
445
+ // 异步验证(检查用户名是否已存在)
446
+ const exists = await checkUsernameExists(value);
447
+ if (exists) {
448
+ return { error: 'USERNAME_EXISTS', message: '用户名已存在' };
449
+ }
450
+ return true;
451
+ })
452
+ .label('用户名')
453
+ });
454
+ ```
455
+
456
+ ### 6.2 条件验证
457
+
458
+ ```typescript
459
+ const schema = dsl({
460
+ userType: dsl('string!').label('用户类型'),
461
+
462
+ companyName: dsl('string')
463
+ .when('userType', {
464
+ is: 'company',
465
+ then: dsl('string!').label('公司名称'), // 企业用户必填
466
+ otherwise: dsl('string').label('公司名称') // 个人用户可选
467
+ })
468
+ });
469
+ ```
470
+
471
+ ### 6.3 Schema 复用和扩展
472
+
473
+ ```typescript
474
+ import { SchemaUtils } from 'schema-dsl';
475
+
476
+ // 基础用户 Schema
477
+ const baseUserSchema = dsl({
478
+ username: dsl('string:3-32!').label('用户名'),
479
+ email: dsl('email!').label('邮箱')
480
+ });
481
+
482
+ // 扩展为管理员 Schema
483
+ const adminSchema = SchemaUtils.extend(baseUserSchema.toJsonSchema(), {
484
+ role: dsl('string!').default('admin').label('角色'),
485
+ permissions: dsl('array<string>').label('权限列表')
486
+ });
487
+
488
+ // 只选择部分字段
489
+ const publicUserSchema = SchemaUtils.pick(
490
+ baseUserSchema.toJsonSchema(),
491
+ ['username']
492
+ );
493
+ ```
494
+
495
+ ---
496
+
497
+ ## 7. 性能优化
498
+
499
+ ### 7.1 Schema 预编译
500
+
501
+ ```typescript
502
+ // 预编译 Schema(只编译一次)
503
+ const schema = dsl({
504
+ email: dsl('email!').label('邮箱')
505
+ });
506
+ schema.compile(); // 预编译
507
+
508
+ // 多次验证(使用缓存的编译结果)
509
+ await validateAsync(schema, data1);
510
+ await validateAsync(schema, data2);
511
+ await validateAsync(schema, data3);
512
+ ```
513
+
514
+ ### 7.2 缓存配置
515
+
516
+ ```typescript
517
+ import { dsl } from 'schema-dsl';
518
+
519
+ // 配置缓存大小
520
+ dsl.config({
521
+ cache: {
522
+ maxSize: 5000, // 缓存条目数
523
+ ttl: 60000 // 过期时间(毫秒)
524
+ }
525
+ });
526
+ ```
527
+
528
+ ---
529
+
530
+ ## 8. 最佳实践总结
531
+
532
+ 1. ✅ **TypeScript 中始终使用 `dsl()` 包裹字符串**
533
+ 2. ✅ **使用 `validateAsync` 进行异步验证**
534
+ 3. ✅ **为验证结果添加泛型类型参数**
535
+ 4. ✅ **复用常用字段定义**
536
+ 5. ✅ **使用 `ValidationError` 类型守卫处理错误**
537
+ 6. ✅ **为用户提供友好的错误消息**
538
+ 7. ✅ **预编译常用的 Schema**
539
+
540
+ ---
541
+
542
+ ## 9. 相关资源
543
+
544
+ - [API 参考文档](./api-reference.md)
545
+ - [DSL 语法完整指南](./dsl-syntax.md)
546
+ - [验证规则参考](./validation-guide.md)
547
+ - [错误处理指南](./error-handling.md)
548
+ - [GitHub 仓库](https://github.com/vextjs/schema-dsl)
549
+
550
+ ---
551
+
552
+ **更新日期**: 2025-12-31
553
+ **文档版本**: v1.0.3
554
+
@@ -474,7 +474,7 @@ new ValidationError(errors, data)
474
474
 
475
475
  ---
476
476
 
477
- **版本**: v2.1.0
477
+ **版本**: v1.0.3
478
478
  **更新日期**: 2025-12-29
479
479
  **作者**: SchemaIO Team
480
480