schema-dsl 1.2.4 → 2.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/CHANGELOG.md +87 -210
- package/README.md +391 -2249
- package/dist/DslBuilder-DQDN0ZxZ.d.cts +341 -0
- package/dist/DslBuilder-DkLaOo9Q.d.ts +341 -0
- package/dist/Validator-C7GsVQOH.d.cts +192 -0
- package/dist/Validator-hFWKGxir.d.ts +192 -0
- package/dist/index.cjs +6594 -0
- package/dist/index.d.cts +1145 -0
- package/dist/index.d.ts +1145 -0
- package/dist/index.js +6528 -0
- package/dist/plugin-CIKtTMtS.d.cts +246 -0
- package/dist/plugin-CIKtTMtS.d.ts +246 -0
- package/dist/plugins/custom-format.cjs +3802 -0
- package/dist/plugins/custom-format.d.cts +12 -0
- package/dist/plugins/custom-format.d.ts +12 -0
- package/dist/plugins/custom-format.js +3772 -0
- package/dist/plugins/custom-type-example.cjs +3795 -0
- package/dist/plugins/custom-type-example.d.cts +8 -0
- package/dist/plugins/custom-type-example.d.ts +8 -0
- package/dist/plugins/custom-type-example.js +3765 -0
- package/dist/plugins/custom-validator.cjs +146 -0
- package/dist/plugins/custom-validator.d.cts +10 -0
- package/dist/plugins/custom-validator.d.ts +10 -0
- package/dist/plugins/custom-validator.js +121 -0
- package/docs/FEATURE-INDEX.md +102 -68
- package/docs/add-custom-locale.md +48 -35
- package/docs/add-keyword.md +24 -0
- package/docs/api-reference.md +396 -154
- package/docs/api.md +13 -0
- package/docs/best-practices-project-structure.md +19 -10
- package/docs/best-practices.md +93 -53
- package/docs/cache-manager.md +23 -15
- package/docs/compile.md +45 -0
- package/docs/conditional-api.md +40 -11
- package/docs/custom-extensions-guide.md +80 -152
- package/docs/design-philosophy.md +76 -71
- package/docs/doc-index.md +324 -0
- package/docs/dsl-syntax.md +69 -19
- package/docs/dynamic-locale.md +24 -14
- package/docs/enum.md +12 -5
- package/docs/error-handling.md +53 -44
- package/docs/export-guide.md +47 -8
- package/docs/export-limitations.md +27 -11
- package/docs/faq.md +86 -67
- package/docs/frontend-i18n-guide.md +26 -12
- package/docs/i18n-user-guide.md +60 -47
- package/docs/i18n.md +51 -32
- package/docs/index.md +48 -0
- package/docs/json-schema-basics.md +40 -0
- package/docs/label-vs-description.md +12 -3
- package/docs/markdown-exporter.md +15 -6
- package/docs/mongodb-exporter.md +11 -4
- package/docs/multi-language.md +26 -0
- package/docs/multi-type-support.md +26 -33
- package/docs/mysql-exporter.md +9 -2
- package/docs/number-operators.md +12 -5
- package/docs/optional-marker-guide.md +28 -23
- package/docs/performance-guide.md +49 -0
- package/docs/plugin-system.md +205 -366
- package/docs/plugin-type-registration.md +34 -0
- package/docs/postgresql-exporter.md +9 -2
- package/docs/public/favicon.svg +5 -0
- package/docs/quick-start.md +37 -363
- package/docs/runtime-locale-support.md +20 -9
- package/docs/schema-helper.md +10 -5
- package/docs/schema-utils-advanced-issues.md +23 -0
- package/docs/schema-utils-best-practices.md +20 -0
- package/docs/schema-utils-chaining.md +7 -0
- package/docs/schema-utils.md +76 -42
- package/docs/security-checklist.md +20 -0
- package/docs/string-extensions.md +17 -9
- package/docs/troubleshooting.md +36 -21
- package/docs/type-converter.md +41 -50
- package/docs/type-reference.md +38 -15
- package/docs/typescript-guide.md +53 -42
- package/docs/union-type-guide.md +11 -1
- package/docs/union-types.md +10 -3
- package/docs/validate-async.md +36 -25
- package/docs/validate-batch.md +49 -0
- package/docs/validate-dsl-object-support.md +33 -28
- package/docs/validate.md +36 -16
- package/docs/validation-guide.md +25 -7
- package/docs/validator.md +39 -0
- package/package.json +85 -27
- package/plugins/custom-format.cjs +8 -0
- package/plugins/custom-type-example.cjs +8 -0
- package/plugins/custom-validator.cjs +8 -0
- package/src/adapters/DslAdapter.ts +111 -0
- package/src/adapters/index.ts +1 -0
- package/src/config/constants.ts +83 -0
- package/src/config/index.ts +2 -0
- package/src/config/patterns.ts +77 -0
- package/src/core/CacheManager.ts +159 -0
- package/src/core/ConditionalBuilder.ts +382 -0
- package/src/core/ConditionalRuntime.ts +28 -0
- package/src/core/ConditionalValidator.ts +255 -0
- package/src/core/DslBuilder.ts +677 -0
- package/src/core/ErrorCodes.ts +38 -0
- package/src/core/ErrorFormatter.ts +271 -0
- package/src/core/JSONSchemaCore.ts +65 -0
- package/src/core/Locale.ts +187 -0
- package/src/core/MessageTemplate.ts +42 -0
- package/src/core/ObjectDslBuilder.ts +64 -0
- package/src/core/PluginManager.ts +326 -0
- package/src/core/StringExtensions.ts +140 -0
- package/src/core/TemplateEngine.ts +44 -0
- package/src/core/Validator.ts +448 -0
- package/src/errors/I18nError.ts +159 -0
- package/src/errors/ValidationError.ts +105 -0
- package/src/exporters/BaseExporter.ts +60 -0
- package/src/exporters/MarkdownExporter.ts +305 -0
- package/src/exporters/MongoDBExporter.ts +126 -0
- package/src/exporters/MySQLExporter.ts +155 -0
- package/src/exporters/PostgreSQLExporter.ts +222 -0
- package/src/exporters/index.ts +18 -0
- package/src/index.ts +633 -0
- package/{lib/locales/en-US.js → src/locales/en-US.ts} +21 -37
- package/{lib/locales/es-ES.js → src/locales/es-ES.ts} +63 -16
- package/{lib/locales/fr-FR.js → src/locales/fr-FR.ts} +74 -27
- package/src/locales/index.ts +103 -0
- package/{lib/locales/ja-JP.js → src/locales/ja-JP.ts} +59 -17
- package/src/locales/types.ts +156 -0
- package/{lib/locales/zh-CN.js → src/locales/zh-CN.ts} +21 -38
- package/src/parser/ConstraintParser.ts +101 -0
- package/src/parser/DslParser.ts +470 -0
- package/src/parser/SchemaCompiler.ts +66 -0
- package/src/parser/TypeRegistry.ts +250 -0
- package/src/parser/index.ts +6 -0
- package/src/plugins/custom-format.ts +126 -0
- package/src/plugins/custom-type-example.ts +108 -0
- package/src/plugins/custom-validator.ts +140 -0
- package/src/types/conditional.ts +28 -0
- package/src/types/config.ts +59 -0
- package/src/types/dsl.ts +131 -0
- package/src/types/error.ts +60 -0
- package/src/types/index.ts +17 -0
- package/src/types/infer.ts +128 -0
- package/src/types/plugin.ts +58 -0
- package/src/types/safe-regex.d.ts +9 -0
- package/src/types/schema.ts +66 -0
- package/src/types/validate.ts +71 -0
- package/src/utils/SchemaHelper.ts +196 -0
- package/src/utils/SchemaUtils.ts +346 -0
- package/src/utils/TypeConverter.ts +215 -0
- package/src/utils/index.ts +10 -0
- package/src/validators/CustomKeywords.ts +477 -0
- package/.eslintignore +0 -11
- package/.eslintrc.json +0 -27
- package/CONTRIBUTING.md +0 -368
- package/STATUS.md +0 -491
- package/changelogs/v1.0.0.md +0 -328
- package/changelogs/v1.0.9.md +0 -367
- package/changelogs/v1.1.0.md +0 -389
- package/changelogs/v1.1.1.md +0 -308
- package/changelogs/v1.1.2.md +0 -183
- package/changelogs/v1.1.3.md +0 -161
- package/changelogs/v1.1.4.md +0 -432
- package/changelogs/v1.1.5.md +0 -493
- package/changelogs/v1.1.6.md +0 -211
- package/changelogs/v1.1.8.md +0 -376
- package/changelogs/v1.2.3.md +0 -124
- package/docs/INDEX.md +0 -252
- package/docs/issues-resolved-summary.md +0 -196
- package/docs/performance-benchmark-report.md +0 -179
- package/docs/performance-quick-reference.md +0 -123
- package/docs/user-questions-answered.md +0 -353
- package/docs/validation-rules-v1.0.2.md +0 -1608
- package/examples/README.md +0 -81
- package/examples/array-dsl-example.js +0 -227
- package/examples/conditional-example.js +0 -288
- package/examples/conditional-non-object.js +0 -129
- package/examples/conditional-validate-example.js +0 -321
- package/examples/custom-extension.js +0 -85
- package/examples/dsl-match-example.js +0 -74
- package/examples/dsl-style.js +0 -118
- package/examples/dynamic-locale-configuration.js +0 -348
- package/examples/dynamic-locale-example.js +0 -287
- package/examples/enum.examples.js +0 -324
- package/examples/export-demo.js +0 -130
- package/examples/express-integration.js +0 -376
- package/examples/i18n-error-handling-complete.js +0 -381
- package/examples/i18n-error-handling-quickstart.md +0 -0
- package/examples/i18n-error.examples.js +0 -181
- package/examples/i18n-full-demo.js +0 -301
- package/examples/i18n-memory-safety.examples.js +0 -268
- package/examples/markdown-export.js +0 -71
- package/examples/middleware-usage.js +0 -93
- package/examples/new-features-comparison.js +0 -315
- package/examples/password-reset/README.md +0 -153
- package/examples/password-reset/schema.js +0 -26
- package/examples/password-reset/test.js +0 -101
- package/examples/plugin-system.examples.js +0 -205
- package/examples/schema-utils-chaining.examples.js +0 -250
- package/examples/simple-example.js +0 -122
- package/examples/slug.examples.js +0 -179
- package/examples/string-extensions.js +0 -297
- package/examples/union-type-example.js +0 -127
- package/examples/union-types-example.js +0 -77
- package/examples/user-registration/README.md +0 -156
- package/examples/user-registration/routes.js +0 -92
- package/examples/user-registration/schema.js +0 -150
- package/examples/user-registration/server.js +0 -74
- package/index.d.ts +0 -3540
- package/index.js +0 -457
- package/index.mjs +0 -60
- package/lib/adapters/DslAdapter.js +0 -871
- package/lib/adapters/index.js +0 -20
- package/lib/config/constants.js +0 -286
- package/lib/config/patterns/common.js +0 -47
- package/lib/config/patterns/creditCard.js +0 -9
- package/lib/config/patterns/idCard.js +0 -9
- package/lib/config/patterns/index.js +0 -9
- package/lib/config/patterns/licensePlate.js +0 -4
- package/lib/config/patterns/passport.js +0 -4
- package/lib/config/patterns/phone.js +0 -9
- package/lib/config/patterns/postalCode.js +0 -5
- package/lib/core/CacheManager.js +0 -376
- package/lib/core/ConditionalBuilder.js +0 -503
- package/lib/core/DslBuilder.js +0 -1400
- package/lib/core/ErrorCodes.js +0 -233
- package/lib/core/ErrorFormatter.js +0 -445
- package/lib/core/JSONSchemaCore.js +0 -347
- package/lib/core/Locale.js +0 -130
- package/lib/core/MessageTemplate.js +0 -98
- package/lib/core/PluginManager.js +0 -448
- package/lib/core/StringExtensions.js +0 -240
- package/lib/core/Validator.js +0 -654
- package/lib/errors/I18nError.js +0 -328
- package/lib/errors/ValidationError.js +0 -191
- package/lib/exporters/MarkdownExporter.js +0 -420
- package/lib/exporters/MongoDBExporter.js +0 -162
- package/lib/exporters/MySQLExporter.js +0 -212
- package/lib/exporters/PostgreSQLExporter.js +0 -289
- package/lib/exporters/index.js +0 -24
- package/lib/locales/index.js +0 -8
- package/lib/utils/LRUCache.js +0 -174
- package/lib/utils/SchemaHelper.js +0 -240
- package/lib/utils/SchemaUtils.js +0 -445
- package/lib/utils/TypeConverter.js +0 -245
- package/lib/utils/index.js +0 -13
- package/lib/validators/CustomKeywords.js +0 -616
- package/lib/validators/index.js +0 -11
|
@@ -1,381 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* schema-dsl 多语言错误处理完整示例
|
|
3
|
-
*
|
|
4
|
-
* 展示如何动态配置多语言来使用 dsl.error.throw('account.notFound')
|
|
5
|
-
*
|
|
6
|
-
* @version 1.1.5+
|
|
7
|
-
* @author schema-dsl Team
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
const { dsl, Locale } = require('schema-dsl');
|
|
11
|
-
|
|
12
|
-
// ============================================================
|
|
13
|
-
// 第一步:配置语言包
|
|
14
|
-
// ============================================================
|
|
15
|
-
|
|
16
|
-
console.log('📚 步骤1:配置多语言包\n');
|
|
17
|
-
|
|
18
|
-
// 方式1:使用 Locale.addLocale() 添加单个语言
|
|
19
|
-
Locale.addLocale('zh-CN', {
|
|
20
|
-
// 字符串格式(向后兼容)
|
|
21
|
-
'user.notFound': '用户不存在',
|
|
22
|
-
|
|
23
|
-
// 对象格式(v1.1.5+ 推荐)- 统一数字错误码
|
|
24
|
-
'account.notFound': {
|
|
25
|
-
code: 40001,
|
|
26
|
-
message: '账户不存在'
|
|
27
|
-
},
|
|
28
|
-
'account.insufficientBalance': {
|
|
29
|
-
code: 40002,
|
|
30
|
-
message: '余额不足,当前余额{{#balance}}元,需要{{#required}}元'
|
|
31
|
-
},
|
|
32
|
-
'order.notPaid': {
|
|
33
|
-
code: 50001,
|
|
34
|
-
message: '订单未支付'
|
|
35
|
-
},
|
|
36
|
-
'permission.denied': {
|
|
37
|
-
code: 40003,
|
|
38
|
-
message: '您没有权限执行此操作'
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
Locale.addLocale('en-US', {
|
|
43
|
-
'user.notFound': 'User not found',
|
|
44
|
-
|
|
45
|
-
'account.notFound': {
|
|
46
|
-
code: 40001, // 相同的数字码
|
|
47
|
-
message: 'Account not found'
|
|
48
|
-
},
|
|
49
|
-
'account.insufficientBalance': {
|
|
50
|
-
code: 40002,
|
|
51
|
-
message: 'Insufficient balance: current {{#balance}}, required {{#required}}'
|
|
52
|
-
},
|
|
53
|
-
'order.notPaid': {
|
|
54
|
-
code: 50001,
|
|
55
|
-
message: 'Order not paid'
|
|
56
|
-
},
|
|
57
|
-
'permission.denied': {
|
|
58
|
-
code: 40003,
|
|
59
|
-
message: 'Permission denied'
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
Locale.addLocale('ja-JP', {
|
|
64
|
-
'user.notFound': 'ユーザーが見つかりません',
|
|
65
|
-
|
|
66
|
-
'account.notFound': {
|
|
67
|
-
code: 40001,
|
|
68
|
-
message: 'アカウントが見つかりません'
|
|
69
|
-
},
|
|
70
|
-
'account.insufficientBalance': {
|
|
71
|
-
code: 40002,
|
|
72
|
-
message: '残高不足: 現在{{#balance}}、必要{{#required}}'
|
|
73
|
-
},
|
|
74
|
-
'order.notPaid': {
|
|
75
|
-
code: 50001,
|
|
76
|
-
message: '注文が未払いです'
|
|
77
|
-
},
|
|
78
|
-
'permission.denied': {
|
|
79
|
-
code: 40003,
|
|
80
|
-
message: 'アクセス権限がありません'
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
// 方式2:批量配置(使用 dsl.config)
|
|
85
|
-
dsl.config({
|
|
86
|
-
i18n: {
|
|
87
|
-
'zh-CN': {
|
|
88
|
-
'payment.failed': {
|
|
89
|
-
code: 50002,
|
|
90
|
-
message: '支付失败:{{#reason}}'
|
|
91
|
-
}
|
|
92
|
-
},
|
|
93
|
-
'en-US': {
|
|
94
|
-
'payment.failed': {
|
|
95
|
-
code: 50002,
|
|
96
|
-
message: 'Payment failed: {{#reason}}'
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
console.log('✅ 语言包配置完成\n');
|
|
103
|
-
|
|
104
|
-
// ============================================================
|
|
105
|
-
// 第二步:设置默认语言
|
|
106
|
-
// ============================================================
|
|
107
|
-
|
|
108
|
-
console.log('📚 步骤2:设置默认语言\n');
|
|
109
|
-
|
|
110
|
-
Locale.setLocale('zh-CN');
|
|
111
|
-
console.log(`✅ 默认语言设置为: ${Locale.getLocale()}\n`);
|
|
112
|
-
|
|
113
|
-
// ============================================================
|
|
114
|
-
// 第三步:使用 dsl.error 抛出多语言错误
|
|
115
|
-
// ============================================================
|
|
116
|
-
|
|
117
|
-
console.log('📚 步骤3:使用 dsl.error 抛出多语言错误\n');
|
|
118
|
-
|
|
119
|
-
// 3.1 使用默认语言(全局语言)
|
|
120
|
-
console.log('--- 3.1 使用默认语言(全局语言)---');
|
|
121
|
-
try {
|
|
122
|
-
dsl.error.throw('account.notFound');
|
|
123
|
-
} catch (error) {
|
|
124
|
-
console.log('错误码:', error.code); // 40001
|
|
125
|
-
console.log('原始Key:', error.originalKey); // 'account.notFound'
|
|
126
|
-
console.log('错误消息:', error.message); // '账户不存在'
|
|
127
|
-
console.log('语言:', error.locale); // 'zh-CN'
|
|
128
|
-
console.log('状态码:', error.statusCode); // 400
|
|
129
|
-
console.log();
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// 3.2 运行时指定语言(推荐用于API)⭐
|
|
133
|
-
console.log('--- 3.2 运行时指定语言(英文)---');
|
|
134
|
-
try {
|
|
135
|
-
dsl.error.throw('account.notFound', {}, 404, 'en-US');
|
|
136
|
-
} catch (error) {
|
|
137
|
-
console.log('错误码:', error.code); // 40001
|
|
138
|
-
console.log('原始Key:', error.originalKey); // 'account.notFound'
|
|
139
|
-
console.log('错误消息:', error.message); // 'Account not found'
|
|
140
|
-
console.log('语言:', error.locale); // 'en-US'
|
|
141
|
-
console.log();
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// 3.3 带参数的错误消息
|
|
145
|
-
console.log('--- 3.3 带参数的错误消息(中文)---');
|
|
146
|
-
try {
|
|
147
|
-
dsl.error.throw('account.insufficientBalance', {
|
|
148
|
-
balance: 50,
|
|
149
|
-
required: 100
|
|
150
|
-
}, 400, 'zh-CN');
|
|
151
|
-
} catch (error) {
|
|
152
|
-
console.log('错误消息:', error.message);
|
|
153
|
-
// '余额不足,当前余额50元,需要100元'
|
|
154
|
-
console.log('参数:', error.params);
|
|
155
|
-
console.log();
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
console.log('--- 3.4 带参数的错误消息(英文)---');
|
|
159
|
-
try {
|
|
160
|
-
dsl.error.throw('account.insufficientBalance', {
|
|
161
|
-
balance: 50,
|
|
162
|
-
required: 100
|
|
163
|
-
}, 400, 'en-US');
|
|
164
|
-
} catch (error) {
|
|
165
|
-
console.log('错误消息:', error.message);
|
|
166
|
-
// 'Insufficient balance: current 50, required 100'
|
|
167
|
-
console.log();
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// ============================================================
|
|
171
|
-
// 第四步:使用 dsl.error.create(创建但不抛出)
|
|
172
|
-
// ============================================================
|
|
173
|
-
|
|
174
|
-
console.log('📚 步骤4:使用 dsl.error.create(创建但不抛出)\n');
|
|
175
|
-
|
|
176
|
-
const error1 = dsl.error.create('account.notFound', {}, 404, 'zh-CN');
|
|
177
|
-
console.log('中文错误:', error1.message);
|
|
178
|
-
|
|
179
|
-
const error2 = dsl.error.create('account.notFound', {}, 404, 'en-US');
|
|
180
|
-
console.log('英文错误:', error2.message);
|
|
181
|
-
|
|
182
|
-
const error3 = dsl.error.create('account.notFound', {}, 404, 'ja-JP');
|
|
183
|
-
console.log('日文错误:', error3.message);
|
|
184
|
-
console.log();
|
|
185
|
-
|
|
186
|
-
// ============================================================
|
|
187
|
-
// 第五步:使用 dsl.error.assert(断言方式)
|
|
188
|
-
// ============================================================
|
|
189
|
-
|
|
190
|
-
console.log('📚 步骤5:使用 dsl.error.assert(断言方式)\n');
|
|
191
|
-
|
|
192
|
-
// 模拟数据
|
|
193
|
-
const account = null;
|
|
194
|
-
const user = { role: 'user' };
|
|
195
|
-
|
|
196
|
-
// 5.1 断言账户存在
|
|
197
|
-
console.log('--- 5.1 断言账户存在(中文)---');
|
|
198
|
-
try {
|
|
199
|
-
dsl.error.assert(account, 'account.notFound', {}, 404, 'zh-CN');
|
|
200
|
-
console.log('账户存在');
|
|
201
|
-
} catch (error) {
|
|
202
|
-
console.log('断言失败:', error.message);
|
|
203
|
-
console.log();
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// 5.2 断言权限
|
|
207
|
-
console.log('--- 5.2 断言权限(英文)---');
|
|
208
|
-
try {
|
|
209
|
-
dsl.error.assert(
|
|
210
|
-
user.role === 'admin',
|
|
211
|
-
'permission.denied',
|
|
212
|
-
{},
|
|
213
|
-
403,
|
|
214
|
-
'en-US'
|
|
215
|
-
);
|
|
216
|
-
console.log('权限通过');
|
|
217
|
-
} catch (error) {
|
|
218
|
-
console.log('断言失败:', error.message);
|
|
219
|
-
console.log();
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// ============================================================
|
|
223
|
-
// 第六步:错误判断(error.is())
|
|
224
|
-
// ============================================================
|
|
225
|
-
|
|
226
|
-
console.log('📚 步骤6:错误判断(error.is())\n');
|
|
227
|
-
|
|
228
|
-
try {
|
|
229
|
-
dsl.error.throw('account.notFound');
|
|
230
|
-
} catch (error) {
|
|
231
|
-
// 方式1:使用 originalKey 判断
|
|
232
|
-
if (error.is('account.notFound')) {
|
|
233
|
-
console.log('✅ 使用 originalKey 判断成功');
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// 方式2:使用数字 code 判断(v1.1.5+)
|
|
237
|
-
if (error.is(40001)) {
|
|
238
|
-
console.log('✅ 使用数字 code 判断成功');
|
|
239
|
-
}
|
|
240
|
-
console.log();
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// ============================================================
|
|
244
|
-
// 第七步:Express/Koa 中的实际应用
|
|
245
|
-
// ============================================================
|
|
246
|
-
|
|
247
|
-
console.log('📚 步骤7:Express/Koa 中的实际应用\n');
|
|
248
|
-
|
|
249
|
-
// 模拟 Express 请求处理
|
|
250
|
-
function expressHandler(req, res) {
|
|
251
|
-
try {
|
|
252
|
-
// 从请求头获取语言
|
|
253
|
-
const locale = req.headers['accept-language'] || 'zh-CN';
|
|
254
|
-
|
|
255
|
-
// 模拟业务逻辑
|
|
256
|
-
const account = findAccount(req.params.id);
|
|
257
|
-
|
|
258
|
-
// 使用运行时语言抛出错误
|
|
259
|
-
dsl.error.assert(account, 'account.notFound', {}, 404, locale);
|
|
260
|
-
|
|
261
|
-
// 检查余额
|
|
262
|
-
dsl.error.assert(
|
|
263
|
-
account.balance >= req.body.amount,
|
|
264
|
-
'account.insufficientBalance',
|
|
265
|
-
{
|
|
266
|
-
balance: account.balance,
|
|
267
|
-
required: req.body.amount
|
|
268
|
-
},
|
|
269
|
-
400,
|
|
270
|
-
locale
|
|
271
|
-
);
|
|
272
|
-
|
|
273
|
-
res.json({ success: true, account });
|
|
274
|
-
} catch (error) {
|
|
275
|
-
// 返回多语言错误
|
|
276
|
-
res.status(error.statusCode).json(error.toJSON());
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// 模拟中文请求
|
|
281
|
-
console.log('--- 模拟中文请求 ---');
|
|
282
|
-
const req1 = {
|
|
283
|
-
headers: { 'accept-language': 'zh-CN' },
|
|
284
|
-
params: { id: '123' },
|
|
285
|
-
body: { amount: 100 }
|
|
286
|
-
};
|
|
287
|
-
const res1 = {
|
|
288
|
-
json: (data) => console.log('响应:', JSON.stringify(data, null, 2)),
|
|
289
|
-
status: (code) => ({ json: (data) => {
|
|
290
|
-
console.log(`状态码: ${code}`);
|
|
291
|
-
console.log('响应:', JSON.stringify(data, null, 2));
|
|
292
|
-
}})
|
|
293
|
-
};
|
|
294
|
-
expressHandler(req1, res1);
|
|
295
|
-
console.log();
|
|
296
|
-
|
|
297
|
-
// 模拟英文请求
|
|
298
|
-
console.log('--- 模拟英文请求 ---');
|
|
299
|
-
const req2 = {
|
|
300
|
-
headers: { 'accept-language': 'en-US' },
|
|
301
|
-
params: { id: '123' },
|
|
302
|
-
body: { amount: 100 }
|
|
303
|
-
};
|
|
304
|
-
const res2 = {
|
|
305
|
-
json: (data) => console.log('响应:', JSON.stringify(data, null, 2)),
|
|
306
|
-
status: (code) => ({ json: (data) => {
|
|
307
|
-
console.log(`状态码: ${code}`);
|
|
308
|
-
console.log('响应:', JSON.stringify(data, null, 2));
|
|
309
|
-
}})
|
|
310
|
-
};
|
|
311
|
-
expressHandler(req2, res2);
|
|
312
|
-
console.log();
|
|
313
|
-
|
|
314
|
-
// ============================================================
|
|
315
|
-
// 第八步:前端统一错误处理
|
|
316
|
-
// ============================================================
|
|
317
|
-
|
|
318
|
-
console.log('📚 步骤8:前端统一错误处理示例\n');
|
|
319
|
-
|
|
320
|
-
// 前端错误处理示例(JavaScript)
|
|
321
|
-
const frontendErrorHandler = `
|
|
322
|
-
// 前端统一错误处理(使用数字 code)
|
|
323
|
-
async function handleRequest() {
|
|
324
|
-
try {
|
|
325
|
-
const response = await fetch('/api/account/123');
|
|
326
|
-
const data = await response.json();
|
|
327
|
-
|
|
328
|
-
if (!response.ok) {
|
|
329
|
-
throw data; // 服务端返回的错误对象
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
return data;
|
|
333
|
-
} catch (error) {
|
|
334
|
-
// 根据数字 code 统一处理,不受语言影响
|
|
335
|
-
switch (error.code) {
|
|
336
|
-
case 40001: // ACCOUNT_NOT_FOUND
|
|
337
|
-
showNotFoundPage();
|
|
338
|
-
break;
|
|
339
|
-
case 40002: // INSUFFICIENT_BALANCE
|
|
340
|
-
showTopUpDialog(error.params);
|
|
341
|
-
break;
|
|
342
|
-
case 50001: // ORDER_NOT_PAID
|
|
343
|
-
showPaymentDialog();
|
|
344
|
-
break;
|
|
345
|
-
default:
|
|
346
|
-
showGenericError(error.message);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
`;
|
|
351
|
-
|
|
352
|
-
console.log(frontendErrorHandler);
|
|
353
|
-
|
|
354
|
-
// ============================================================
|
|
355
|
-
// 工具函数
|
|
356
|
-
// ============================================================
|
|
357
|
-
|
|
358
|
-
function findAccount(id) {
|
|
359
|
-
// 模拟查询失败
|
|
360
|
-
return null;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// ============================================================
|
|
364
|
-
// 总结
|
|
365
|
-
// ============================================================
|
|
366
|
-
|
|
367
|
-
console.log('\n📝 总结\n');
|
|
368
|
-
console.log('✅ 1. 使用 Locale.addLocale() 或 dsl.config() 配置语言包');
|
|
369
|
-
console.log('✅ 2. 使用 Locale.setLocale() 设置默认语言');
|
|
370
|
-
console.log('✅ 3. 使用 dsl.error.throw() 抛出多语言错误');
|
|
371
|
-
console.log('✅ 4. 使用 dsl.error.create() 创建错误(不抛出)');
|
|
372
|
-
console.log('✅ 5. 使用 dsl.error.assert() 断言式错误处理');
|
|
373
|
-
console.log('✅ 6. 使用 error.is() 判断错误类型(支持 key 和 code)');
|
|
374
|
-
console.log('✅ 7. API 开发中使用运行时语言(推荐)');
|
|
375
|
-
console.log('✅ 8. 前端使用统一的数字 code 处理错误');
|
|
376
|
-
console.log('\n🎯 关键点:');
|
|
377
|
-
console.log(' - 对象格式支持统一数字错误码(v1.1.5+)');
|
|
378
|
-
console.log(' - 运行时语言不改变全局状态(并发安全)');
|
|
379
|
-
console.log(' - 完全向后兼容字符串格式');
|
|
380
|
-
console.log(' - 多语言共享相同的数字 code');
|
|
381
|
-
console.log('\n📖 完整文档:docs/error-handling.md 和 docs/runtime-locale-support.md');
|
|
File without changes
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* I18nError 使用示例
|
|
3
|
-
*
|
|
4
|
-
* 统一的多语言错误抛出机制
|
|
5
|
-
*
|
|
6
|
-
* @version 1.1.1
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const { I18nError, dsl, Locale } = require('../index');
|
|
10
|
-
|
|
11
|
-
console.log('=== I18nError 使用示例 ===\n');
|
|
12
|
-
|
|
13
|
-
// ========== 1. 基础用法 ==========
|
|
14
|
-
console.log('1. 基础用法:');
|
|
15
|
-
try {
|
|
16
|
-
throw I18nError.create('account.notFound');
|
|
17
|
-
} catch (error) {
|
|
18
|
-
console.log('错误:', error.message); // "账户不存在"
|
|
19
|
-
console.log('代码:', error.code); // "account.notFound"
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// ========== 2. 带参数的错误 ==========
|
|
23
|
-
console.log('\n2. 带参数的错误:');
|
|
24
|
-
try {
|
|
25
|
-
throw I18nError.create('account.insufficientBalance', {
|
|
26
|
-
balance: 50,
|
|
27
|
-
required: 100
|
|
28
|
-
});
|
|
29
|
-
} catch (error) {
|
|
30
|
-
console.log('错误:', error.message); // "余额不足,当前余额50,需要100"
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// ========== 3. 使用 throw 方法 ==========
|
|
34
|
-
console.log('\n3. 使用 throw 方法(直接抛错):');
|
|
35
|
-
try {
|
|
36
|
-
I18nError.throw('user.noPermission');
|
|
37
|
-
} catch (error) {
|
|
38
|
-
console.log('错误:', error.message); // "没有管理员权限"
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// ========== 4. 使用 assert 断言 ==========
|
|
42
|
-
console.log('\n4. 使用 assert 断言:');
|
|
43
|
-
const account = { balance: 50 };
|
|
44
|
-
|
|
45
|
-
try {
|
|
46
|
-
I18nError.assert(account.balance >= 100, 'account.insufficientBalance', {
|
|
47
|
-
balance: account.balance,
|
|
48
|
-
required: 100
|
|
49
|
-
});
|
|
50
|
-
} catch (error) {
|
|
51
|
-
console.log('错误:', error.message);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// ========== 5. dsl.error 快捷方法 ==========
|
|
55
|
-
console.log('\n5. dsl.error 快捷方法:');
|
|
56
|
-
try {
|
|
57
|
-
dsl.error.throw('order.notPaid');
|
|
58
|
-
} catch (error) {
|
|
59
|
-
console.log('错误:', error.message); // "订单未支付"
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// ========== 6. 多语言支持 ==========
|
|
63
|
-
console.log('\n6. 多语言支持:');
|
|
64
|
-
try {
|
|
65
|
-
// 中文
|
|
66
|
-
Locale.setLocale('zh-CN');
|
|
67
|
-
throw I18nError.create('account.notFound');
|
|
68
|
-
} catch (error) {
|
|
69
|
-
console.log('中文:', error.message); // "账户不存在"
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
try {
|
|
73
|
-
// 英文
|
|
74
|
-
Locale.setLocale('en-US');
|
|
75
|
-
throw I18nError.create('account.notFound');
|
|
76
|
-
} catch (error) {
|
|
77
|
-
console.log('英文:', error.message); // "Account not found"
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// 恢复中文
|
|
81
|
-
Locale.setLocale('zh-CN');
|
|
82
|
-
|
|
83
|
-
// ========== 7. 实际业务场景 =========
|
|
84
|
-
console.log('\n7. 实际业务场景:');
|
|
85
|
-
|
|
86
|
-
// 场景1:账户验证函数
|
|
87
|
-
function getAccount(id) {
|
|
88
|
-
const account = id === '123' ? { id: '123', balance: 50, status: 'active' } : null;
|
|
89
|
-
|
|
90
|
-
// 断言账户存在
|
|
91
|
-
I18nError.assert(account, 'account.notFound');
|
|
92
|
-
|
|
93
|
-
// 断言账户状态
|
|
94
|
-
I18nError.assert(account.status === 'active', 'account.inactive');
|
|
95
|
-
|
|
96
|
-
// 断言余额充足
|
|
97
|
-
I18nError.assert(
|
|
98
|
-
account.balance >= 100,
|
|
99
|
-
'account.insufficientBalance',
|
|
100
|
-
{ balance: account.balance, required: 100 }
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
return account;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
try {
|
|
107
|
-
getAccount('123');
|
|
108
|
-
} catch (error) {
|
|
109
|
-
console.log('业务错误:', error.message);
|
|
110
|
-
console.log('错误代码:', error.code);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// 场景2:与 dsl.if 结合
|
|
114
|
-
console.log('\n8. 与 dsl.if 结合使用:');
|
|
115
|
-
function validateUser(user) {
|
|
116
|
-
// 使用 dsl.if 进行数据验证
|
|
117
|
-
dsl.if(d => !d)
|
|
118
|
-
.message('user.notFound')
|
|
119
|
-
.and(d => !d.isVerified)
|
|
120
|
-
.message('user.notVerified')
|
|
121
|
-
.assert(user);
|
|
122
|
-
|
|
123
|
-
// 使用 I18nError 进行业务逻辑验证
|
|
124
|
-
I18nError.assert(user.role === 'admin', 'user.noPermission');
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
try {
|
|
128
|
-
validateUser({ isVerified: true, role: 'user' });
|
|
129
|
-
} catch (error) {
|
|
130
|
-
console.log('验证错误:', error.message);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// ========== 9. Express/Koa 中间件 ==========
|
|
134
|
-
console.log('\n9. Express/Koa 错误处理:');
|
|
135
|
-
|
|
136
|
-
// Express 错误处理中间件
|
|
137
|
-
function expressErrorHandler(error, req, res, next) {
|
|
138
|
-
if (error instanceof I18nError) {
|
|
139
|
-
return res.status(error.statusCode).json(error.toJSON());
|
|
140
|
-
}
|
|
141
|
-
next(error);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// 模拟使用
|
|
145
|
-
const mockError = I18nError.create('account.notFound', {}, 404);
|
|
146
|
-
const mockRes = {
|
|
147
|
-
status: (code) => {
|
|
148
|
-
console.log('HTTP Status:', code);
|
|
149
|
-
return mockRes;
|
|
150
|
-
},
|
|
151
|
-
json: (data) => {
|
|
152
|
-
console.log('Response:', JSON.stringify(data, null, 2));
|
|
153
|
-
return mockRes;
|
|
154
|
-
}
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
expressErrorHandler(mockError, {}, mockRes, () => {});
|
|
158
|
-
|
|
159
|
-
// ========== 10. 自定义状态码 ==========
|
|
160
|
-
console.log('\n10. 自定义状态码:');
|
|
161
|
-
try {
|
|
162
|
-
throw I18nError.create('user.notFound', {}, 404);
|
|
163
|
-
} catch (error) {
|
|
164
|
-
console.log('状态码:', error.statusCode); // 404
|
|
165
|
-
console.log('错误:', error.message);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// ========== 11. 错误检查 ==========
|
|
169
|
-
console.log('\n11. 错误类型检查:');
|
|
170
|
-
try {
|
|
171
|
-
throw I18nError.create('account.notFound');
|
|
172
|
-
} catch (error) {
|
|
173
|
-
if (error instanceof I18nError) {
|
|
174
|
-
console.log('是 I18nError:', true);
|
|
175
|
-
console.log('是账户不存在:', error.is('account.notFound'));
|
|
176
|
-
console.log('是用户不存在:', error.is('user.notFound'));
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
console.log('\n=== 示例完成 ===');
|
|
181
|
-
|