schema-dsl 1.1.2 → 1.1.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.
- package/CHANGELOG.md +75 -1236
- package/README.md +221 -2
- package/STATUS.md +67 -2
- package/changelogs/v1.0.0.md +328 -0
- package/changelogs/v1.0.9.md +367 -0
- package/changelogs/v1.1.0.md +389 -0
- package/changelogs/v1.1.1.md +308 -0
- package/changelogs/v1.1.2.md +183 -0
- package/changelogs/v1.1.3.md +161 -0
- package/changelogs/v1.1.4.md +432 -0
- package/docs/dsl-syntax.md +14 -3
- package/docs/optional-marker-guide.md +321 -0
- package/docs/runtime-locale-support.md +443 -0
- package/index.d.ts +126 -10
- package/index.js +6 -3
- package/index.mjs +2 -2
- package/lib/core/DslBuilder.js +11 -2
- package/lib/core/ErrorFormatter.js +6 -1
- package/lib/errors/I18nError.js +21 -6
- package/package.json +1 -1
package/lib/core/DslBuilder.js
CHANGED
|
@@ -123,11 +123,20 @@ class DslBuilder {
|
|
|
123
123
|
processedDsl = trimmed.replace(/^array!/, 'array:') + '!';
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
// 🔴 处理必填标记 ! 和可选标记 ?
|
|
127
|
+
// 优先级:! > ?(如果同时存在,! 优先)
|
|
126
128
|
this._required = processedDsl.endsWith('!');
|
|
127
|
-
|
|
129
|
+
this._optional = processedDsl.endsWith('?') && !this._required;
|
|
130
|
+
|
|
131
|
+
let dslWithoutMarker = processedDsl;
|
|
132
|
+
if (this._required) {
|
|
133
|
+
dslWithoutMarker = processedDsl.slice(0, -1);
|
|
134
|
+
} else if (this._optional) {
|
|
135
|
+
dslWithoutMarker = processedDsl.slice(0, -1);
|
|
136
|
+
}
|
|
128
137
|
|
|
129
138
|
// 简单解析为基础Schema(避免循环依赖)
|
|
130
|
-
this._baseSchema = this._parseSimple(
|
|
139
|
+
this._baseSchema = this._parseSimple(dslWithoutMarker);
|
|
131
140
|
|
|
132
141
|
// 扩展属性
|
|
133
142
|
this._customMessages = {};
|
|
@@ -277,7 +277,12 @@ class ErrorFormatter {
|
|
|
277
277
|
// 映射 min/max 以匹配模板
|
|
278
278
|
min: limit,
|
|
279
279
|
max: limit,
|
|
280
|
-
expected: err.params ? err.params.type : undefined
|
|
280
|
+
expected: err.params ? err.params.type : undefined,
|
|
281
|
+
// ✅ 修复:添加 actual 参数 - 实际接收到的数据类型
|
|
282
|
+
actual: err.data === null ? 'null' :
|
|
283
|
+
err.data === undefined ? 'undefined' :
|
|
284
|
+
Array.isArray(err.data) ? 'array' :
|
|
285
|
+
typeof err.data
|
|
281
286
|
};
|
|
282
287
|
|
|
283
288
|
message = this._interpolate(message, interpolateData);
|
package/lib/errors/I18nError.js
CHANGED
|
@@ -95,6 +95,7 @@ class I18nError extends Error {
|
|
|
95
95
|
* @param {string} code - 错误代码(多语言 key)
|
|
96
96
|
* @param {Object} params - 错误参数
|
|
97
97
|
* @param {number} statusCode - HTTP 状态码
|
|
98
|
+
* @param {string} locale - 语言环境(可选,不传则使用全局语言)
|
|
98
99
|
* @returns {I18nError} 错误实例
|
|
99
100
|
*
|
|
100
101
|
* @example
|
|
@@ -104,9 +105,13 @@ class I18nError extends Error {
|
|
|
104
105
|
* @example
|
|
105
106
|
* // 直接抛出
|
|
106
107
|
* throw I18nError.create('error.notFound', { resource: '用户' });
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* // 运行时指定语言
|
|
111
|
+
* const error = I18nError.create('error.notFound', {}, 404, 'en-US');
|
|
107
112
|
*/
|
|
108
|
-
static create(code, params = {}, statusCode = 400) {
|
|
109
|
-
return new I18nError(code, params, statusCode);
|
|
113
|
+
static create(code, params = {}, statusCode = 400, locale = null) {
|
|
114
|
+
return new I18nError(code, params, statusCode, locale);
|
|
110
115
|
}
|
|
111
116
|
|
|
112
117
|
/**
|
|
@@ -115,14 +120,19 @@ class I18nError extends Error {
|
|
|
115
120
|
* @param {string} code - 错误代码(多语言 key)
|
|
116
121
|
* @param {Object} params - 错误参数
|
|
117
122
|
* @param {number} statusCode - HTTP 状态码
|
|
123
|
+
* @param {string} locale - 语言环境(可选,不传则使用全局语言)
|
|
118
124
|
* @throws {I18nError} 直接抛出错误
|
|
119
125
|
*
|
|
120
126
|
* @example
|
|
121
127
|
* I18nError.throw('error.notFound', { resource: '用户' });
|
|
122
128
|
* // 等同于:throw I18nError.create('error.notFound', { resource: '用户' });
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* // 运行时指定语言
|
|
132
|
+
* I18nError.throw('error.notFound', {}, 404, 'en-US');
|
|
123
133
|
*/
|
|
124
|
-
static throw(code, params = {}, statusCode = 400) {
|
|
125
|
-
throw new I18nError(code, params, statusCode);
|
|
134
|
+
static throw(code, params = {}, statusCode = 400, locale = null) {
|
|
135
|
+
throw new I18nError(code, params, statusCode, locale);
|
|
126
136
|
}
|
|
127
137
|
|
|
128
138
|
/**
|
|
@@ -132,6 +142,7 @@ class I18nError extends Error {
|
|
|
132
142
|
* @param {string} code - 错误代码(多语言 key)
|
|
133
143
|
* @param {Object} params - 错误参数
|
|
134
144
|
* @param {number} statusCode - HTTP 状态码
|
|
145
|
+
* @param {string} locale - 语言环境(可选,不传则使用全局语言)
|
|
135
146
|
* @throws {I18nError} 条件为 false 时抛出错误
|
|
136
147
|
*
|
|
137
148
|
* @example
|
|
@@ -144,10 +155,14 @@ class I18nError extends Error {
|
|
|
144
155
|
* 'account.insufficientBalance',
|
|
145
156
|
* { balance: account.balance, required: 100 }
|
|
146
157
|
* );
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* // 运行时指定语言
|
|
161
|
+
* I18nError.assert(account, 'account.notFound', {}, 404, 'en-US');
|
|
147
162
|
*/
|
|
148
|
-
static assert(condition, code, params = {}, statusCode = 400) {
|
|
163
|
+
static assert(condition, code, params = {}, statusCode = 400, locale = null) {
|
|
149
164
|
if (!condition) {
|
|
150
|
-
throw new I18nError(code, params, statusCode);
|
|
165
|
+
throw new I18nError(code, params, statusCode, locale);
|
|
151
166
|
}
|
|
152
167
|
}
|
|
153
168
|
|