schema-dsl 1.2.5 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/CHANGELOG.md +130 -238
  2. package/LICENSE +21 -21
  3. package/README.md +628 -2486
  4. package/dist/DslBuilder-BIgQOAXp.d.ts +343 -0
  5. package/dist/DslBuilder-CjHTucNQ.d.cts +343 -0
  6. package/dist/Validator-CllRdrY0.d.ts +192 -0
  7. package/dist/Validator-D6okG9tr.d.cts +192 -0
  8. package/dist/index.cjs +6640 -0
  9. package/dist/index.d.cts +1151 -0
  10. package/dist/index.d.ts +1151 -0
  11. package/dist/index.js +6574 -0
  12. package/dist/plugin-CIKtTMtS.d.cts +246 -0
  13. package/dist/plugin-CIKtTMtS.d.ts +246 -0
  14. package/dist/plugins/custom-format.cjs +3818 -0
  15. package/dist/plugins/custom-format.d.cts +12 -0
  16. package/dist/plugins/custom-format.d.ts +12 -0
  17. package/dist/plugins/custom-format.js +3788 -0
  18. package/dist/plugins/custom-type-example.cjs +3811 -0
  19. package/dist/plugins/custom-type-example.d.cts +8 -0
  20. package/dist/plugins/custom-type-example.d.ts +8 -0
  21. package/dist/plugins/custom-type-example.js +3781 -0
  22. package/dist/plugins/custom-validator.cjs +144 -0
  23. package/dist/plugins/custom-validator.d.cts +10 -0
  24. package/dist/plugins/custom-validator.d.ts +10 -0
  25. package/dist/plugins/custom-validator.js +119 -0
  26. package/docs/FEATURE-INDEX.md +553 -519
  27. package/docs/add-custom-locale.md +496 -483
  28. package/docs/add-keyword.md +24 -0
  29. package/docs/api-reference.md +1047 -805
  30. package/docs/api.md +13 -0
  31. package/docs/best-practices-project-structure.md +417 -408
  32. package/docs/best-practices.md +712 -672
  33. package/docs/cache-manager.md +344 -336
  34. package/docs/compile.md +45 -0
  35. package/docs/conditional-api.md +1307 -1278
  36. package/docs/custom-extensions-guide.md +339 -411
  37. package/docs/design-philosophy.md +606 -601
  38. package/docs/doc-index.md +324 -0
  39. package/docs/dsl-syntax.md +714 -664
  40. package/docs/dynamic-locale.md +608 -598
  41. package/docs/enum.md +482 -475
  42. package/docs/error-handling.md +1975 -1966
  43. package/docs/export-guide.md +501 -462
  44. package/docs/export-limitations.md +567 -551
  45. package/docs/faq.md +596 -577
  46. package/docs/frontend-i18n-guide.md +307 -293
  47. package/docs/i18n-user-guide.md +487 -474
  48. package/docs/i18n.md +476 -457
  49. package/docs/index.md +48 -0
  50. package/docs/json-schema-basics.md +40 -0
  51. package/docs/label-vs-description.md +271 -262
  52. package/docs/markdown-exporter.md +406 -397
  53. package/docs/mongodb-exporter.md +302 -295
  54. package/docs/multi-language.md +26 -0
  55. package/docs/multi-type-support.md +322 -329
  56. package/docs/mysql-exporter.md +280 -273
  57. package/docs/number-operators.md +449 -442
  58. package/docs/optional-marker-guide.md +326 -321
  59. package/docs/performance-guide.md +49 -0
  60. package/docs/plugin-system.md +381 -542
  61. package/docs/plugin-type-registration.md +34 -0
  62. package/docs/postgresql-exporter.md +311 -304
  63. package/docs/public/favicon.svg +5 -0
  64. package/docs/quick-start.md +435 -761
  65. package/docs/runtime-locale-support.md +532 -521
  66. package/docs/schema-helper.md +345 -340
  67. package/docs/schema-utils-advanced-issues.md +23 -0
  68. package/docs/schema-utils-best-practices.md +20 -0
  69. package/docs/schema-utils-chaining.md +150 -143
  70. package/docs/schema-utils.md +524 -490
  71. package/docs/security-checklist.md +20 -0
  72. package/docs/string-extensions.md +488 -480
  73. package/docs/troubleshooting.md +486 -471
  74. package/docs/type-converter.md +310 -319
  75. package/docs/type-reference.md +242 -219
  76. package/docs/typescript-guide.md +584 -573
  77. package/docs/union-type-guide.md +157 -147
  78. package/docs/union-types.md +284 -277
  79. package/docs/validate-async.md +491 -480
  80. package/docs/validate-batch.md +49 -0
  81. package/docs/validate-dsl-object-support.md +578 -573
  82. package/docs/validate.md +506 -486
  83. package/docs/validation-guide.md +502 -484
  84. package/docs/validator.md +39 -0
  85. package/package.json +131 -73
  86. package/plugins/custom-format.cjs +8 -0
  87. package/plugins/custom-type-example.cjs +8 -0
  88. package/plugins/custom-validator.cjs +8 -0
  89. package/src/adapters/DslAdapter.ts +111 -0
  90. package/src/adapters/index.ts +1 -0
  91. package/src/config/constants.ts +83 -0
  92. package/src/config/index.ts +2 -0
  93. package/src/config/patterns.ts +77 -0
  94. package/src/core/CacheManager.ts +169 -0
  95. package/src/core/ConditionalBuilder.ts +382 -0
  96. package/src/core/ConditionalRuntime.ts +28 -0
  97. package/src/core/ConditionalValidator.ts +255 -0
  98. package/src/core/DslBuilder.ts +687 -0
  99. package/src/core/ErrorCodes.ts +38 -0
  100. package/src/core/ErrorFormatter.ts +271 -0
  101. package/src/core/JSONSchemaCore.ts +65 -0
  102. package/src/core/Locale.ts +187 -0
  103. package/src/core/MessageTemplate.ts +42 -0
  104. package/src/core/ObjectDslBuilder.ts +64 -0
  105. package/src/core/PluginManager.ts +326 -0
  106. package/src/core/StringExtensions.ts +140 -0
  107. package/src/core/TemplateEngine.ts +44 -0
  108. package/src/core/Validator.ts +448 -0
  109. package/src/errors/I18nError.ts +159 -0
  110. package/src/errors/ValidationError.ts +105 -0
  111. package/src/exporters/BaseExporter.ts +60 -0
  112. package/src/exporters/MarkdownExporter.ts +305 -0
  113. package/src/exporters/MongoDBExporter.ts +126 -0
  114. package/src/exporters/MySQLExporter.ts +156 -0
  115. package/src/exporters/PostgreSQLExporter.ts +222 -0
  116. package/src/exporters/index.ts +18 -0
  117. package/src/index.ts +651 -0
  118. package/{lib/locales/en-US.js → src/locales/en-US.ts} +160 -176
  119. package/{lib/locales/es-ES.js → src/locales/es-ES.ts} +160 -113
  120. package/{lib/locales/fr-FR.js → src/locales/fr-FR.ts} +160 -113
  121. package/src/locales/index.ts +103 -0
  122. package/{lib/locales/ja-JP.js → src/locales/ja-JP.ts} +160 -118
  123. package/src/locales/types.ts +156 -0
  124. package/{lib/locales/zh-CN.js → src/locales/zh-CN.ts} +160 -177
  125. package/src/parser/ConstraintParser.ts +101 -0
  126. package/src/parser/DslParser.ts +470 -0
  127. package/src/parser/SchemaCompiler.ts +66 -0
  128. package/src/parser/TypeRegistry.ts +250 -0
  129. package/src/parser/index.ts +6 -0
  130. package/src/plugins/custom-format.ts +124 -0
  131. package/src/plugins/custom-type-example.ts +106 -0
  132. package/src/plugins/custom-validator.ts +138 -0
  133. package/src/types/conditional.ts +28 -0
  134. package/src/types/config.ts +59 -0
  135. package/src/types/dsl.ts +131 -0
  136. package/src/types/error.ts +60 -0
  137. package/src/types/index.ts +17 -0
  138. package/src/types/infer.ts +128 -0
  139. package/src/types/plugin.ts +58 -0
  140. package/src/types/safe-regex.d.ts +9 -0
  141. package/src/types/schema.ts +66 -0
  142. package/src/types/validate.ts +71 -0
  143. package/src/utils/SchemaHelper.ts +196 -0
  144. package/src/utils/SchemaUtils.ts +365 -0
  145. package/src/utils/TypeConverter.ts +215 -0
  146. package/src/utils/index.ts +10 -0
  147. package/src/validators/CustomKeywords.ts +477 -0
  148. package/.eslintignore +0 -11
  149. package/.eslintrc.json +0 -27
  150. package/CONTRIBUTING.md +0 -368
  151. package/STATUS.md +0 -491
  152. package/changelogs/v1.0.0.md +0 -328
  153. package/changelogs/v1.0.9.md +0 -367
  154. package/changelogs/v1.1.0.md +0 -389
  155. package/changelogs/v1.1.1.md +0 -308
  156. package/changelogs/v1.1.2.md +0 -183
  157. package/changelogs/v1.1.3.md +0 -161
  158. package/changelogs/v1.1.4.md +0 -432
  159. package/changelogs/v1.1.5.md +0 -493
  160. package/changelogs/v1.1.6.md +0 -211
  161. package/changelogs/v1.1.8.md +0 -376
  162. package/changelogs/v1.2.3.md +0 -124
  163. package/docs/INDEX.md +0 -252
  164. package/docs/issues-resolved-summary.md +0 -196
  165. package/docs/performance-benchmark-report.md +0 -179
  166. package/docs/performance-quick-reference.md +0 -123
  167. package/docs/user-questions-answered.md +0 -353
  168. package/docs/validation-rules-v1.0.2.md +0 -1608
  169. package/examples/README.md +0 -81
  170. package/examples/array-dsl-example.js +0 -227
  171. package/examples/conditional-example.js +0 -288
  172. package/examples/conditional-non-object.js +0 -129
  173. package/examples/conditional-validate-example.js +0 -321
  174. package/examples/custom-extension.js +0 -85
  175. package/examples/dsl-match-example.js +0 -74
  176. package/examples/dsl-style.js +0 -118
  177. package/examples/dynamic-locale-configuration.js +0 -348
  178. package/examples/dynamic-locale-example.js +0 -287
  179. package/examples/enum.examples.js +0 -324
  180. package/examples/export-demo.js +0 -130
  181. package/examples/express-integration.js +0 -376
  182. package/examples/i18n-error-handling-complete.js +0 -381
  183. package/examples/i18n-error-handling-quickstart.md +0 -0
  184. package/examples/i18n-error.examples.js +0 -181
  185. package/examples/i18n-full-demo.js +0 -301
  186. package/examples/i18n-memory-safety.examples.js +0 -268
  187. package/examples/markdown-export.js +0 -71
  188. package/examples/middleware-usage.js +0 -93
  189. package/examples/new-features-comparison.js +0 -315
  190. package/examples/password-reset/README.md +0 -153
  191. package/examples/password-reset/schema.js +0 -26
  192. package/examples/password-reset/test.js +0 -101
  193. package/examples/plugin-system.examples.js +0 -205
  194. package/examples/schema-utils-chaining.examples.js +0 -250
  195. package/examples/simple-example.js +0 -122
  196. package/examples/slug.examples.js +0 -179
  197. package/examples/string-extensions.js +0 -297
  198. package/examples/union-type-example.js +0 -127
  199. package/examples/union-types-example.js +0 -77
  200. package/examples/user-registration/README.md +0 -156
  201. package/examples/user-registration/routes.js +0 -92
  202. package/examples/user-registration/schema.js +0 -150
  203. package/examples/user-registration/server.js +0 -74
  204. package/index.d.ts +0 -3658
  205. package/index.js +0 -475
  206. package/index.mjs +0 -60
  207. package/lib/adapters/DslAdapter.js +0 -995
  208. package/lib/adapters/index.js +0 -20
  209. package/lib/config/constants.js +0 -286
  210. package/lib/config/patterns/common.js +0 -47
  211. package/lib/config/patterns/creditCard.js +0 -9
  212. package/lib/config/patterns/idCard.js +0 -9
  213. package/lib/config/patterns/index.js +0 -9
  214. package/lib/config/patterns/licensePlate.js +0 -4
  215. package/lib/config/patterns/passport.js +0 -4
  216. package/lib/config/patterns/phone.js +0 -9
  217. package/lib/config/patterns/postalCode.js +0 -5
  218. package/lib/core/CacheManager.js +0 -376
  219. package/lib/core/ConditionalBuilder.js +0 -503
  220. package/lib/core/DslBuilder.js +0 -1589
  221. package/lib/core/ErrorCodes.js +0 -233
  222. package/lib/core/ErrorFormatter.js +0 -445
  223. package/lib/core/JSONSchemaCore.js +0 -347
  224. package/lib/core/Locale.js +0 -130
  225. package/lib/core/MessageTemplate.js +0 -98
  226. package/lib/core/PluginManager.js +0 -448
  227. package/lib/core/StringExtensions.js +0 -240
  228. package/lib/core/Validator.js +0 -654
  229. package/lib/errors/I18nError.js +0 -328
  230. package/lib/errors/ValidationError.js +0 -191
  231. package/lib/exporters/MarkdownExporter.js +0 -420
  232. package/lib/exporters/MongoDBExporter.js +0 -162
  233. package/lib/exporters/MySQLExporter.js +0 -212
  234. package/lib/exporters/PostgreSQLExporter.js +0 -289
  235. package/lib/exporters/index.js +0 -24
  236. package/lib/locales/index.js +0 -8
  237. package/lib/utils/LRUCache.js +0 -174
  238. package/lib/utils/SchemaHelper.js +0 -240
  239. package/lib/utils/SchemaUtils.js +0 -445
  240. package/lib/utils/TypeConverter.js +0 -245
  241. package/lib/utils/index.js +0 -13
  242. package/lib/validators/CustomKeywords.js +0 -616
  243. package/lib/validators/index.js +0 -11
@@ -1,118 +0,0 @@
1
- /**
2
- * DSL风格API示例 v2.0
3
- *
4
- * 演示新的DSL Builder Pattern:
5
- * - 简单场景:纯字符串DSL
6
- * - 复杂场景:字符串直接链式调用(✨ 无需 dsl() 包裹)
7
- */
8
-
9
- const { dsl, Validator } = require('../index');
10
-
11
- // ========== 1. 简单场景:纯字符串DSL ==========
12
-
13
- const simpleSchema = dsl({
14
- username: 'string:3-32!', // 必填字符串,长度3-32
15
- email: 'email!', // 必填邮箱
16
- age: 'number:18-120', // 可选数字,范围18-120
17
- status: 'active|inactive|pending', // 枚举值
18
- tags: 'array<string:1-20>', // 字符串数组,每项长度1-20
19
- });
20
-
21
- console.log('========== 简单Schema(纯DSL)==========');
22
- console.log(JSON.stringify(simpleSchema, null, 2));
23
-
24
- // ========== 2. 复杂场景:字符串直接链式调用 ✨ ==========
25
-
26
- const complexSchema = dsl({
27
- // ✨ 超简洁!字符串直接调用链式方法,无需 dsl() 包裹
28
- username: 'string:3-32!'
29
- .pattern(/^[a-zA-Z0-9_]+$/)
30
- .messages({
31
- 'pattern': '只能包含字母、数字和下划线'
32
- })
33
- .label('用户名')
34
- .description('用户登录名'),
35
-
36
- // ✨ 邮箱:直接链式
37
- email: 'email!'
38
- .label('邮箱地址')
39
- .messages({
40
- 'format': '请输入有效的邮箱地址'
41
- }),
42
-
43
- // ✨ 密码:复杂正则 + 自定义消息
44
- password: 'string:8-64!'
45
- .pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$/)
46
- .messages({
47
- 'min': '密码长度不能少于8位',
48
- 'pattern': '密码必须包含大小写字母和数字'
49
- })
50
- .label('密码'),
51
-
52
- // 年龄:简单约束(无需链式)
53
- age: 'number:18-120',
54
-
55
- // 角色:枚举(无需链式)
56
- role: 'user|admin|moderator',
57
-
58
- // 嵌套对象:混合使用
59
- profile: {
60
- bio: 'string:500', // 简单:纯DSL
61
- website: 'url' // ✨ 也可以链式
62
- .description('个人主页'),
63
- avatar: 'url'
64
- .label('头像URL')
65
- }
66
- });
67
-
68
- console.log('\n========== 复杂Schema(DSL + 链式)==========');
69
- console.log(JSON.stringify(complexSchema, null, 2));
70
-
71
- // ========== 3. 验证数据 ==========
72
-
73
- const { validate } = require('../index');
74
-
75
- const testData = {
76
- username: 'john_doe',
77
- email: 'john@example.com',
78
- password: 'Password123',
79
- age: 25,
80
- role: 'user',
81
- profile: {
82
- bio: 'Full-stack developer',
83
- website: 'https://example.com',
84
- avatar: 'https://example.com/avatar.jpg'
85
- }
86
- };
87
-
88
- console.log('\n========== 验证数据 ==========');
89
- const result = validate(complexSchema, testData);
90
- console.log('验证结果:', result.valid ? '✅ 通过' : '❌ 失败');
91
- if (!result.valid) {
92
- console.log('错误:', result.errors);
93
- }
94
-
95
- // ========== 4. 展示API优势 ==========
96
-
97
- console.log('\n========== API对比 ==========');
98
-
99
- // v1.0: 需要 dsl() 包裹
100
- console.log('❌ v1.0(需要 dsl()):');
101
- console.log(` email: dsl('email!')
102
- .pattern(/custom/)
103
- .messages({ 'pattern': '格式不正确' })
104
- .label('邮箱地址')`);
105
-
106
- // v2.0: 字符串直接链式
107
- console.log('\n✅ v2.0(字符串直接链式):');
108
- console.log(` email: 'email!'
109
- .pattern(/custom/)
110
- .messages({ 'pattern': '格式不正确' })
111
- .label('邮箱地址')`);
112
-
113
- console.log('\n✅ DSL v2.0 示例运行完成!');
114
- console.log('💡 提示:简单字段用纯DSL,复杂字段直接链式调用');
115
- console.log('🎉 特色:字符串直接调用方法,无需 dsl() 包裹!');
116
-
117
-
118
-
@@ -1,348 +0,0 @@
1
- /**
2
- * 动态多语言配置完整示例
3
- *
4
- * 演示如何在各种场景下动态配置和切换语言
5
- */
6
-
7
- const { dsl, validate, Locale } = require('../index');
8
-
9
- console.log('========== 动态多语言配置示例 ==========\n');
10
-
11
- // ========================================
12
- // 示例 1: 基本的语言切换
13
- // ========================================
14
- console.log('【示例 1】基本的语言切换\n');
15
-
16
- const userSchema = dsl({
17
- email: 'email!',
18
- age: 'number:18-120!'
19
- });
20
-
21
- // 中文环境
22
- Locale.setLocale('zh-CN');
23
- let result = validate(userSchema, { email: 'invalid', age: 10 });
24
- console.log('中文错误:', result.errors.map(e => e.message).join(', '));
25
-
26
- // 切换到英文
27
- Locale.setLocale('en-US');
28
- result = validate(userSchema, { email: 'invalid', age: 10 });
29
- console.log('英文错误:', result.errors.map(e => e.message).join(', '));
30
-
31
- console.log('\n' + '='.repeat(60) + '\n');
32
-
33
- // ========================================
34
- // 示例 2: 使用 dsl.config() 批量配置语言包
35
- // ========================================
36
- console.log('【示例 2】使用 dsl.config() 批量配置\n');
37
-
38
- dsl.config({
39
- locales: {
40
- 'zh-CN': {
41
- 'custom.tooYoung': '{{#label}}年龄太小,需满18岁',
42
- 'custom.emailTaken': '{{#label}}已被占用'
43
- },
44
- 'en-US': {
45
- 'custom.tooYoung': '{{#label}} is too young, must be 18+',
46
- 'custom.emailTaken': '{{#label}} is already taken'
47
- }
48
- }
49
- });
50
-
51
- // 测试自定义消息
52
- Locale.setLocale('zh-CN');
53
- console.log('中文自定义:', Locale.getMessage('custom.tooYoung'));
54
-
55
- Locale.setLocale('en-US');
56
- console.log('英文自定义:', Locale.getMessage('custom.tooYoung'));
57
-
58
- console.log('\n' + '='.repeat(60) + '\n');
59
-
60
- // ========================================
61
- // 示例 3: 模拟前端语言切换
62
- // ========================================
63
- console.log('【示例 3】模拟前端语言切换\n');
64
-
65
- class LanguageManager {
66
- constructor() {
67
- this.locale = 'en-US';
68
- this.storage = {}; // 模拟 localStorage
69
- }
70
-
71
- // 获取用户偏好语言
72
- getUserPreference() {
73
- return this.storage.userLanguage || this.detectBrowserLanguage();
74
- }
75
-
76
- // 检测浏览器语言(模拟)
77
- detectBrowserLanguage() {
78
- // 模拟 navigator.language
79
- const browserLang = 'zh-CN';
80
- const langMap = {
81
- 'zh': 'zh-CN',
82
- 'zh-CN': 'zh-CN',
83
- 'en': 'en-US',
84
- 'en-US': 'en-US'
85
- };
86
- return langMap[browserLang] || langMap[browserLang.split('-')[0]] || 'en-US';
87
- }
88
-
89
- // 切换语言
90
- changeLanguage(newLocale) {
91
- console.log(`切换语言: ${this.locale} → ${newLocale}`);
92
- this.locale = newLocale;
93
- this.storage.userLanguage = newLocale;
94
- Locale.setLocale(newLocale);
95
- }
96
-
97
- // 初始化
98
- init() {
99
- const preferredLang = this.getUserPreference();
100
- console.log(`初始化语言: ${preferredLang}`);
101
- this.changeLanguage(preferredLang);
102
- }
103
- }
104
-
105
- const langManager = new LanguageManager();
106
- langManager.init();
107
-
108
- // 验证(使用检测到的语言)
109
- result = validate(userSchema, { email: 'test', age: 15 });
110
- console.log('当前语言:', Locale.getLocale());
111
- console.log('错误消息:', result.errors.map(e => e.message).join(', '));
112
-
113
- // 用户手动切换
114
- langManager.changeLanguage('en-US');
115
- result = validate(userSchema, { email: 'test', age: 15 });
116
- console.log('错误消息:', result.errors.map(e => e.message).join(', '));
117
-
118
- console.log('\n' + '='.repeat(60) + '\n');
119
-
120
- // ========================================
121
- // 示例 4: 模拟服务端请求语言切换
122
- // ========================================
123
- console.log('【示例 4】服务端请求语言切换(安全模式)\n');
124
-
125
- function validateWithLocale(schema, data, requestLocale) {
126
- // 保存原始语言
127
- const originalLocale = Locale.getLocale();
128
-
129
- try {
130
- // 临时切换到请求的语言
131
- Locale.setLocale(requestLocale);
132
-
133
- // 执行验证
134
- const result = validate(schema, data);
135
-
136
- return {
137
- locale: requestLocale,
138
- errors: result.errors
139
- };
140
- } finally {
141
- // 恢复原始语言(重要!)
142
- Locale.setLocale(originalLocale);
143
- }
144
- }
145
-
146
- // 模拟多个并发请求
147
- console.log('请求1 (中文):');
148
- const req1 = validateWithLocale(userSchema, { email: 'bad' }, 'zh-CN');
149
- console.log(' 语言:', req1.locale);
150
- console.log(' 错误:', req1.errors.map(e => e.message).join(', '));
151
-
152
- console.log('\n请求2 (英文):');
153
- const req2 = validateWithLocale(userSchema, { email: 'bad' }, 'en-US');
154
- console.log(' 语言:', req2.locale);
155
- console.log(' 错误:', req2.errors.map(e => e.message).join(', '));
156
-
157
- console.log('\n请求3 (日文):');
158
- const req3 = validateWithLocale(userSchema, { email: 'bad' }, 'ja-JP');
159
- console.log(' 语言:', req3.locale);
160
- console.log(' 错误:', req3.errors.map(e => e.message).join(', '));
161
-
162
- console.log('\n全局语言未被污染:', Locale.getLocale());
163
-
164
- console.log('\n' + '='.repeat(60) + '\n');
165
-
166
- // ========================================
167
- // 示例 5: 动态加载语言包(模拟)
168
- // ========================================
169
- console.log('【示例 5】动态加载语言包\n');
170
-
171
- class LocaleLoader {
172
- constructor() {
173
- this.loadedLocales = new Set(['en-US']); // 默认已加载
174
- }
175
-
176
- // 模拟异步加载语言包
177
- async loadLocale(locale) {
178
- if (this.loadedLocales.has(locale)) {
179
- console.log(`语言包 "${locale}" 已加载,跳过`);
180
- return;
181
- }
182
-
183
- console.log(`正在加载语言包 "${locale}"...`);
184
-
185
- // 模拟网络延迟
186
- await new Promise(resolve => setTimeout(resolve, 100));
187
-
188
- // 模拟语言包内容
189
- const mockLanguagePacks = {
190
- 'fr-FR': {
191
- 'required': '{{#label}} est requis',
192
- 'format.email': '{{#label}} doit être une adresse e-mail valide'
193
- },
194
- 'de-DE': {
195
- 'required': '{{#label}} ist erforderlich',
196
- 'format.email': '{{#label}} muss eine gültige E-Mail-Adresse sein'
197
- }
198
- };
199
-
200
- const messages = mockLanguagePacks[locale];
201
- if (messages) {
202
- Locale.addLocale(locale, messages);
203
- this.loadedLocales.add(locale);
204
- console.log(`✅ 语言包 "${locale}" 加载成功`);
205
- } else {
206
- console.log(`❌ 语言包 "${locale}" 不存在,回退到英文`);
207
- return 'en-US';
208
- }
209
- }
210
-
211
- // 切换语言(带自动加载)
212
- async changeLanguage(locale) {
213
- await this.loadLocale(locale);
214
- Locale.setLocale(locale);
215
- console.log(`当前语言: ${Locale.getLocale()}\n`);
216
- }
217
- }
218
-
219
- const loader = new LocaleLoader();
220
-
221
- (async () => {
222
- // 加载法语
223
- await loader.changeLanguage('fr-FR');
224
- result = validate(userSchema, { email: 'mauvais' });
225
- console.log('法语错误:', result.errors.map(e => e.message).join(', '));
226
-
227
- console.log('');
228
-
229
- // 加载德语
230
- await loader.changeLanguage('de-DE');
231
- result = validate(userSchema, { email: 'schlecht' });
232
- console.log('德语错误:', result.errors.map(e => e.message).join(', '));
233
-
234
- console.log('\n' + '='.repeat(60) + '\n');
235
-
236
- // ========================================
237
- // 示例 6: 同时获取多种语言的错误消息
238
- // ========================================
239
- console.log('【示例 6】同时获取多种语言的错误消息\n');
240
-
241
- const ErrorFormatter = require('../lib/core/ErrorFormatter');
242
- const Validator = require('../lib/core/Validator');
243
-
244
- const validator = new Validator();
245
- const invalidData = { email: 'invalid-email', age: 10 };
246
-
247
- // 执行验证
248
- const validationResult = validator.validate(userSchema, invalidData);
249
-
250
- // 获取多种语言的错误消息
251
- const languages = ['zh-CN', 'en-US', 'ja-JP'];
252
- const multiLangErrors = {};
253
-
254
- languages.forEach(lang => {
255
- const formatter = new ErrorFormatter(lang);
256
- multiLangErrors[lang] = formatter.formatDetailed(validationResult.errors);
257
- });
258
-
259
- console.log('多语言错误消息:');
260
- console.log(JSON.stringify(multiLangErrors, null, 2));
261
-
262
- console.log('\n' + '='.repeat(60) + '\n');
263
-
264
- // ========================================
265
- // 示例 7: 完整的前端应用场景
266
- // ========================================
267
- console.log('【示例 7】完整的前端应用场景\n');
268
-
269
- class FormValidator {
270
- constructor() {
271
- this.schema = dsl({
272
- username: 'string:3-20!'.label('username'),
273
- email: 'email!'.label('email'),
274
- password: 'string:8-32!'.label('password')
275
- });
276
-
277
- // 初始化语言
278
- this.initLanguage();
279
- }
280
-
281
- initLanguage() {
282
- // 1. 从 localStorage 恢复
283
- const savedLang = this.getStoredLanguage();
284
-
285
- // 2. 如果没有保存,检测浏览器语言
286
- const lang = savedLang || this.detectBrowserLanguage();
287
-
288
- // 3. 设置语言
289
- this.changeLanguage(lang);
290
-
291
- console.log(`应用启动,语言初始化为: ${lang}`);
292
- }
293
-
294
- getStoredLanguage() {
295
- // 模拟 localStorage.getItem
296
- return null; // 首次访问
297
- }
298
-
299
- detectBrowserLanguage() {
300
- // 模拟 navigator.language
301
- return 'zh-CN';
302
- }
303
-
304
- changeLanguage(lang) {
305
- console.log(`用户选择语言: ${lang}`);
306
- Locale.setLocale(lang);
307
- // 模拟 localStorage.setItem
308
- }
309
-
310
- validateForm(formData) {
311
- const result = validate(this.schema, formData);
312
-
313
- return {
314
- valid: result.valid,
315
- errors: result.errors.map(err => ({
316
- field: err.path,
317
- message: err.message
318
- }))
319
- };
320
- }
321
- }
322
-
323
- const formValidator = new FormValidator();
324
-
325
- // 模拟表单提交
326
- console.log('\n提交表单(中文环境):');
327
- let formResult = formValidator.validateForm({
328
- username: 'ab',
329
- email: 'bad',
330
- password: '123'
331
- });
332
- console.log('验证结果:', JSON.stringify(formResult, null, 2));
333
-
334
- // 用户切换语言
335
- console.log('\n用户切换到英文:');
336
- formValidator.changeLanguage('en-US');
337
-
338
- console.log('\n再次提交表单(英文环境):');
339
- formResult = formValidator.validateForm({
340
- username: 'ab',
341
- email: 'bad',
342
- password: '123'
343
- });
344
- console.log('验证结果:', JSON.stringify(formResult, null, 2));
345
-
346
- console.log('\n========== 所有示例完成 ==========');
347
- })();
348
-