koatty_validation 1.6.1 → 1.6.3
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/.turbo/turbo-build.log +120 -0
- package/.turbo/turbo-test.log +8 -0
- package/CHANGELOG.md +29 -26
- package/dist/index.d.ts +29 -9
- package/dist/index.js +228 -204
- package/dist/index.mjs +228 -204
- package/dist/package.json +10 -14
- package/package.json +21 -26
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* @Author: richen
|
|
3
|
-
* @Date:
|
|
3
|
+
* @Date: 2026-01-28 12:40:10
|
|
4
4
|
* @License: BSD (3-Clause)
|
|
5
5
|
* @Copyright (c) - <richenlin(at)gmail.com>
|
|
6
6
|
* @HomePage: https://koatty.org/
|
|
@@ -820,6 +820,209 @@ function plateNumber(value) {
|
|
|
820
820
|
}
|
|
821
821
|
}
|
|
822
822
|
|
|
823
|
+
/**
|
|
824
|
+
* Improved error handling mechanism
|
|
825
|
+
* @author richen
|
|
826
|
+
*/
|
|
827
|
+
/**
|
|
828
|
+
* Error message internationalization
|
|
829
|
+
*/
|
|
830
|
+
const ERROR_MESSAGES = {
|
|
831
|
+
zh: {
|
|
832
|
+
// Chinese localization validation
|
|
833
|
+
IsCnName: '必须是有效的中文姓名',
|
|
834
|
+
IsIdNumber: '必须是有效的身份证号码',
|
|
835
|
+
IsZipCode: '必须是有效的邮政编码',
|
|
836
|
+
IsMobile: '必须是有效的手机号码',
|
|
837
|
+
IsPlateNumber: '必须是有效的车牌号码',
|
|
838
|
+
// Basic validation
|
|
839
|
+
IsNotEmpty: '不能为空',
|
|
840
|
+
IsDate: '必须是有效的日期',
|
|
841
|
+
IsEmail: '必须是有效的邮箱地址',
|
|
842
|
+
IsIP: '必须是有效的IP地址',
|
|
843
|
+
IsPhoneNumber: '必须是有效的电话号码',
|
|
844
|
+
IsUrl: '必须是有效的URL地址',
|
|
845
|
+
IsHash: '必须是有效的哈希值',
|
|
846
|
+
// Comparison validation
|
|
847
|
+
Equals: '必须等于 {comparison}',
|
|
848
|
+
NotEquals: '不能等于 {comparison}',
|
|
849
|
+
Contains: '必须包含 {seed}',
|
|
850
|
+
IsIn: '必须是以下值之一: {possibleValues}',
|
|
851
|
+
IsNotIn: '不能是以下值之一: {possibleValues}',
|
|
852
|
+
Gt: '必须大于 {min}',
|
|
853
|
+
Gte: '必须大于或等于 {min}',
|
|
854
|
+
Lt: '必须小于 {max}',
|
|
855
|
+
Lte: '必须小于或等于 {max}',
|
|
856
|
+
// Common errors
|
|
857
|
+
invalidParameter: '参数 {field} 无效',
|
|
858
|
+
validationFailed: '验证失败',
|
|
859
|
+
},
|
|
860
|
+
en: {
|
|
861
|
+
// Chinese localization validators
|
|
862
|
+
IsCnName: 'must be a valid Chinese name',
|
|
863
|
+
IsIdNumber: 'must be a valid ID number',
|
|
864
|
+
IsZipCode: 'must be a valid zip code',
|
|
865
|
+
IsMobile: 'must be a valid mobile number',
|
|
866
|
+
IsPlateNumber: 'must be a valid plate number',
|
|
867
|
+
// Basic validators
|
|
868
|
+
IsNotEmpty: 'should not be empty',
|
|
869
|
+
IsDate: 'must be a valid date',
|
|
870
|
+
IsEmail: 'must be a valid email',
|
|
871
|
+
IsIP: 'must be a valid IP address',
|
|
872
|
+
IsPhoneNumber: 'must be a valid phone number',
|
|
873
|
+
IsUrl: 'must be a valid URL',
|
|
874
|
+
IsHash: 'must be a valid hash',
|
|
875
|
+
// Comparison validators
|
|
876
|
+
Equals: 'must equal to {comparison}',
|
|
877
|
+
NotEquals: 'should not equal to {comparison}',
|
|
878
|
+
Contains: 'must contain {seed}',
|
|
879
|
+
IsIn: 'must be one of the following values: {possibleValues}',
|
|
880
|
+
IsNotIn: 'should not be one of the following values: {possibleValues}',
|
|
881
|
+
Gt: 'must be greater than {min}',
|
|
882
|
+
Gte: 'must be greater than or equal to {min}',
|
|
883
|
+
Lt: 'must be less than {max}',
|
|
884
|
+
Lte: 'must be less than or equal to {max}',
|
|
885
|
+
// Common errors
|
|
886
|
+
invalidParameter: 'invalid parameter {field}',
|
|
887
|
+
validationFailed: 'validation failed',
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
/**
|
|
891
|
+
* Enhanced validation error class
|
|
892
|
+
*/
|
|
893
|
+
class KoattyValidationError extends Error {
|
|
894
|
+
constructor(errors, message) {
|
|
895
|
+
const errorMessage = message || 'Validation failed';
|
|
896
|
+
super(errorMessage);
|
|
897
|
+
this.name = 'KoattyValidationError';
|
|
898
|
+
this.errors = errors;
|
|
899
|
+
this.statusCode = 400;
|
|
900
|
+
this.timestamp = new Date();
|
|
901
|
+
// Ensure correct prototype chain
|
|
902
|
+
Object.setPrototypeOf(this, KoattyValidationError.prototype);
|
|
903
|
+
}
|
|
904
|
+
/**
|
|
905
|
+
* Get the first error message
|
|
906
|
+
*/
|
|
907
|
+
getFirstError() {
|
|
908
|
+
return this.errors[0];
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* Get errors for a specific field
|
|
912
|
+
*/
|
|
913
|
+
getFieldErrors(field) {
|
|
914
|
+
return this.errors.filter(error => error.field === field);
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* Convert to JSON format
|
|
918
|
+
*/
|
|
919
|
+
toJSON() {
|
|
920
|
+
return {
|
|
921
|
+
name: this.name,
|
|
922
|
+
message: this.message,
|
|
923
|
+
statusCode: this.statusCode,
|
|
924
|
+
timestamp: this.timestamp,
|
|
925
|
+
errors: this.errors
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
/**
|
|
930
|
+
* Error message formatter
|
|
931
|
+
*/
|
|
932
|
+
class ErrorMessageFormatter {
|
|
933
|
+
constructor(language = 'zh') {
|
|
934
|
+
this.language = 'zh';
|
|
935
|
+
this.language = language;
|
|
936
|
+
}
|
|
937
|
+
/**
|
|
938
|
+
* Set language
|
|
939
|
+
*/
|
|
940
|
+
setLanguage(language) {
|
|
941
|
+
this.language = language;
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Format error message
|
|
945
|
+
*/
|
|
946
|
+
formatMessage(constraint, field, value, context) {
|
|
947
|
+
const messages = ERROR_MESSAGES[this.language];
|
|
948
|
+
let template = messages[constraint] || messages.invalidParameter;
|
|
949
|
+
// Replace placeholders
|
|
950
|
+
template = template.replace('{field}', field);
|
|
951
|
+
// Prioritize values from context, then use passed value
|
|
952
|
+
if (context) {
|
|
953
|
+
Object.entries(context).forEach(([key, val]) => {
|
|
954
|
+
template = template.replace(`{${key}}`, this.formatValue(val));
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
// If there's still a {value} placeholder and value was passed, replace it
|
|
958
|
+
if (value !== undefined && template.includes('{value}')) {
|
|
959
|
+
template = template.replace('{value}', this.formatValue(value));
|
|
960
|
+
}
|
|
961
|
+
return template;
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* Format value for message display
|
|
965
|
+
* @private
|
|
966
|
+
*/
|
|
967
|
+
formatValue(value) {
|
|
968
|
+
if (value === null)
|
|
969
|
+
return 'null';
|
|
970
|
+
if (value === undefined)
|
|
971
|
+
return 'undefined';
|
|
972
|
+
if (typeof value === 'number')
|
|
973
|
+
return String(value);
|
|
974
|
+
if (typeof value === 'string')
|
|
975
|
+
return `"${value}"`;
|
|
976
|
+
if (Array.isArray(value))
|
|
977
|
+
return `[${value.map(v => this.formatValue(v)).join(', ')}]`;
|
|
978
|
+
if (typeof value === 'object') {
|
|
979
|
+
try {
|
|
980
|
+
return JSON.stringify(value);
|
|
981
|
+
}
|
|
982
|
+
catch {
|
|
983
|
+
// Handle circular references
|
|
984
|
+
return '[Circular Reference]';
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
return String(value);
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
/**
|
|
991
|
+
* Global error message formatter instance
|
|
992
|
+
*/
|
|
993
|
+
const errorFormatter = new ErrorMessageFormatter();
|
|
994
|
+
/**
|
|
995
|
+
* Set global language
|
|
996
|
+
*/
|
|
997
|
+
function setValidationLanguage(language) {
|
|
998
|
+
errorFormatter.setLanguage(language);
|
|
999
|
+
}
|
|
1000
|
+
/**
|
|
1001
|
+
* Create validation error
|
|
1002
|
+
*/
|
|
1003
|
+
function createValidationError(field, value, constraint, customMessage, context) {
|
|
1004
|
+
const message = customMessage || errorFormatter.formatMessage(constraint, field, value, context);
|
|
1005
|
+
return {
|
|
1006
|
+
field,
|
|
1007
|
+
value,
|
|
1008
|
+
constraint,
|
|
1009
|
+
message,
|
|
1010
|
+
context
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
/**
|
|
1014
|
+
* Create validation errors in batch
|
|
1015
|
+
*/
|
|
1016
|
+
function createValidationErrors(errors, separator = '; ') {
|
|
1017
|
+
const validationErrors = errors.map(error => createValidationError(error.field, error.value, error.constraint, error.message, error.context));
|
|
1018
|
+
// Generate combined message from all errors
|
|
1019
|
+
const combinedMessage = validationErrors
|
|
1020
|
+
.map(err => err.message)
|
|
1021
|
+
.filter(msg => msg && msg.trim())
|
|
1022
|
+
.join(separator) || 'Validation failed';
|
|
1023
|
+
return new KoattyValidationError(validationErrors, combinedMessage);
|
|
1024
|
+
}
|
|
1025
|
+
|
|
823
1026
|
/*
|
|
824
1027
|
* @Description:
|
|
825
1028
|
* @Usage:
|
|
@@ -879,10 +1082,11 @@ class ValidateClass {
|
|
|
879
1082
|
* @param {*} Clazz
|
|
880
1083
|
* @param {*} data
|
|
881
1084
|
* @param {boolean} [convert=false] auto convert parameters type
|
|
1085
|
+
* @param {ValidationOptions} [options] validation options (returnAllErrors, errorSeparator)
|
|
882
1086
|
* @returns {Promise<any>}
|
|
883
1087
|
* @memberof ValidateClass
|
|
884
1088
|
*/
|
|
885
|
-
async valid(Clazz, data, convert = false) {
|
|
1089
|
+
async valid(Clazz, data, convert = false, options) {
|
|
886
1090
|
let obj = {};
|
|
887
1091
|
if (data instanceof Clazz) {
|
|
888
1092
|
obj = data;
|
|
@@ -898,7 +1102,21 @@ class ValidateClass {
|
|
|
898
1102
|
errors = await classValidator.validate(obj, { skipMissingProperties: true });
|
|
899
1103
|
}
|
|
900
1104
|
if (errors.length > 0) {
|
|
901
|
-
|
|
1105
|
+
// Check if user wants all errors or just the first one
|
|
1106
|
+
if (options === null || options === void 0 ? void 0 : options.returnAllErrors) {
|
|
1107
|
+
// Throw KoattyValidationError with all error details
|
|
1108
|
+
throw createValidationErrors(errors.map(e => ({
|
|
1109
|
+
field: e.property,
|
|
1110
|
+
value: e.value,
|
|
1111
|
+
constraint: Object.keys(e.constraints || {})[0] || 'unknown',
|
|
1112
|
+
message: Object.values(e.constraints || {})[0] || 'Validation failed',
|
|
1113
|
+
context: e.constraints
|
|
1114
|
+
})), options.errorSeparator || '; ');
|
|
1115
|
+
}
|
|
1116
|
+
else {
|
|
1117
|
+
// Default behavior (backward compatible): return only first error
|
|
1118
|
+
throw new Error(Object.values(errors[0].constraints)[0]);
|
|
1119
|
+
}
|
|
902
1120
|
}
|
|
903
1121
|
return obj;
|
|
904
1122
|
}
|
|
@@ -1170,8 +1388,9 @@ function createValidationDecorator(options) {
|
|
|
1170
1388
|
},
|
|
1171
1389
|
defaultMessage(validationArguments) {
|
|
1172
1390
|
const property = validationArguments.property;
|
|
1173
|
-
|
|
1174
|
-
|
|
1391
|
+
const customMessage = (validationOptions === null || validationOptions === void 0 ? void 0 : validationOptions.message) || defaultMessage;
|
|
1392
|
+
return customMessage
|
|
1393
|
+
? customMessage.replace('$property', property)
|
|
1175
1394
|
: `Invalid value for ${property}`;
|
|
1176
1395
|
}
|
|
1177
1396
|
}
|
|
@@ -1210,204 +1429,6 @@ function createParameterizedDecorator(name, validator, defaultMessage) {
|
|
|
1210
1429
|
});
|
|
1211
1430
|
}
|
|
1212
1431
|
|
|
1213
|
-
/**
|
|
1214
|
-
* Improved error handling mechanism
|
|
1215
|
-
* @author richen
|
|
1216
|
-
*/
|
|
1217
|
-
/**
|
|
1218
|
-
* Error message internationalization
|
|
1219
|
-
*/
|
|
1220
|
-
const ERROR_MESSAGES = {
|
|
1221
|
-
zh: {
|
|
1222
|
-
// Chinese localization validation
|
|
1223
|
-
IsCnName: '必须是有效的中文姓名',
|
|
1224
|
-
IsIdNumber: '必须是有效的身份证号码',
|
|
1225
|
-
IsZipCode: '必须是有效的邮政编码',
|
|
1226
|
-
IsMobile: '必须是有效的手机号码',
|
|
1227
|
-
IsPlateNumber: '必须是有效的车牌号码',
|
|
1228
|
-
// Basic validation
|
|
1229
|
-
IsNotEmpty: '不能为空',
|
|
1230
|
-
IsDate: '必须是有效的日期',
|
|
1231
|
-
IsEmail: '必须是有效的邮箱地址',
|
|
1232
|
-
IsIP: '必须是有效的IP地址',
|
|
1233
|
-
IsPhoneNumber: '必须是有效的电话号码',
|
|
1234
|
-
IsUrl: '必须是有效的URL地址',
|
|
1235
|
-
IsHash: '必须是有效的哈希值',
|
|
1236
|
-
// Comparison validation
|
|
1237
|
-
Equals: '必须等于 {comparison}',
|
|
1238
|
-
NotEquals: '不能等于 {comparison}',
|
|
1239
|
-
Contains: '必须包含 {seed}',
|
|
1240
|
-
IsIn: '必须是以下值之一: {possibleValues}',
|
|
1241
|
-
IsNotIn: '不能是以下值之一: {possibleValues}',
|
|
1242
|
-
Gt: '必须大于 {min}',
|
|
1243
|
-
Gte: '必须大于或等于 {min}',
|
|
1244
|
-
Lt: '必须小于 {max}',
|
|
1245
|
-
Lte: '必须小于或等于 {max}',
|
|
1246
|
-
// Common errors
|
|
1247
|
-
invalidParameter: '参数 {field} 无效',
|
|
1248
|
-
validationFailed: '验证失败',
|
|
1249
|
-
},
|
|
1250
|
-
en: {
|
|
1251
|
-
// Chinese localization validators
|
|
1252
|
-
IsCnName: 'must be a valid Chinese name',
|
|
1253
|
-
IsIdNumber: 'must be a valid ID number',
|
|
1254
|
-
IsZipCode: 'must be a valid zip code',
|
|
1255
|
-
IsMobile: 'must be a valid mobile number',
|
|
1256
|
-
IsPlateNumber: 'must be a valid plate number',
|
|
1257
|
-
// Basic validators
|
|
1258
|
-
IsNotEmpty: 'should not be empty',
|
|
1259
|
-
IsDate: 'must be a valid date',
|
|
1260
|
-
IsEmail: 'must be a valid email',
|
|
1261
|
-
IsIP: 'must be a valid IP address',
|
|
1262
|
-
IsPhoneNumber: 'must be a valid phone number',
|
|
1263
|
-
IsUrl: 'must be a valid URL',
|
|
1264
|
-
IsHash: 'must be a valid hash',
|
|
1265
|
-
// Comparison validators
|
|
1266
|
-
Equals: 'must equal to {comparison}',
|
|
1267
|
-
NotEquals: 'should not equal to {comparison}',
|
|
1268
|
-
Contains: 'must contain {seed}',
|
|
1269
|
-
IsIn: 'must be one of the following values: {possibleValues}',
|
|
1270
|
-
IsNotIn: 'should not be one of the following values: {possibleValues}',
|
|
1271
|
-
Gt: 'must be greater than {min}',
|
|
1272
|
-
Gte: 'must be greater than or equal to {min}',
|
|
1273
|
-
Lt: 'must be less than {max}',
|
|
1274
|
-
Lte: 'must be less than or equal to {max}',
|
|
1275
|
-
// Common errors
|
|
1276
|
-
invalidParameter: 'invalid parameter {field}',
|
|
1277
|
-
validationFailed: 'validation failed',
|
|
1278
|
-
}
|
|
1279
|
-
};
|
|
1280
|
-
/**
|
|
1281
|
-
* Enhanced validation error class
|
|
1282
|
-
*/
|
|
1283
|
-
class KoattyValidationError extends Error {
|
|
1284
|
-
constructor(errors, message) {
|
|
1285
|
-
const errorMessage = message || 'Validation failed';
|
|
1286
|
-
super(errorMessage);
|
|
1287
|
-
this.name = 'KoattyValidationError';
|
|
1288
|
-
this.errors = errors;
|
|
1289
|
-
this.statusCode = 400;
|
|
1290
|
-
this.timestamp = new Date();
|
|
1291
|
-
// Ensure correct prototype chain
|
|
1292
|
-
Object.setPrototypeOf(this, KoattyValidationError.prototype);
|
|
1293
|
-
}
|
|
1294
|
-
/**
|
|
1295
|
-
* Get the first error message
|
|
1296
|
-
*/
|
|
1297
|
-
getFirstError() {
|
|
1298
|
-
return this.errors[0];
|
|
1299
|
-
}
|
|
1300
|
-
/**
|
|
1301
|
-
* Get errors for a specific field
|
|
1302
|
-
*/
|
|
1303
|
-
getFieldErrors(field) {
|
|
1304
|
-
return this.errors.filter(error => error.field === field);
|
|
1305
|
-
}
|
|
1306
|
-
/**
|
|
1307
|
-
* Convert to JSON format
|
|
1308
|
-
*/
|
|
1309
|
-
toJSON() {
|
|
1310
|
-
return {
|
|
1311
|
-
name: this.name,
|
|
1312
|
-
message: this.message,
|
|
1313
|
-
statusCode: this.statusCode,
|
|
1314
|
-
timestamp: this.timestamp,
|
|
1315
|
-
errors: this.errors
|
|
1316
|
-
};
|
|
1317
|
-
}
|
|
1318
|
-
}
|
|
1319
|
-
/**
|
|
1320
|
-
* Error message formatter
|
|
1321
|
-
*/
|
|
1322
|
-
class ErrorMessageFormatter {
|
|
1323
|
-
constructor(language = 'zh') {
|
|
1324
|
-
this.language = 'zh';
|
|
1325
|
-
this.language = language;
|
|
1326
|
-
}
|
|
1327
|
-
/**
|
|
1328
|
-
* Set language
|
|
1329
|
-
*/
|
|
1330
|
-
setLanguage(language) {
|
|
1331
|
-
this.language = language;
|
|
1332
|
-
}
|
|
1333
|
-
/**
|
|
1334
|
-
* Format error message
|
|
1335
|
-
*/
|
|
1336
|
-
formatMessage(constraint, field, value, context) {
|
|
1337
|
-
const messages = ERROR_MESSAGES[this.language];
|
|
1338
|
-
let template = messages[constraint] || messages.invalidParameter;
|
|
1339
|
-
// Replace placeholders
|
|
1340
|
-
template = template.replace('{field}', field);
|
|
1341
|
-
// Prioritize values from context, then use passed value
|
|
1342
|
-
if (context) {
|
|
1343
|
-
Object.entries(context).forEach(([key, val]) => {
|
|
1344
|
-
template = template.replace(`{${key}}`, this.formatValue(val));
|
|
1345
|
-
});
|
|
1346
|
-
}
|
|
1347
|
-
// If there's still a {value} placeholder and value was passed, replace it
|
|
1348
|
-
if (value !== undefined && template.includes('{value}')) {
|
|
1349
|
-
template = template.replace('{value}', this.formatValue(value));
|
|
1350
|
-
}
|
|
1351
|
-
return template;
|
|
1352
|
-
}
|
|
1353
|
-
/**
|
|
1354
|
-
* Format value for message display
|
|
1355
|
-
* @private
|
|
1356
|
-
*/
|
|
1357
|
-
formatValue(value) {
|
|
1358
|
-
if (value === null)
|
|
1359
|
-
return 'null';
|
|
1360
|
-
if (value === undefined)
|
|
1361
|
-
return 'undefined';
|
|
1362
|
-
if (typeof value === 'number')
|
|
1363
|
-
return String(value);
|
|
1364
|
-
if (typeof value === 'string')
|
|
1365
|
-
return `"${value}"`;
|
|
1366
|
-
if (Array.isArray(value))
|
|
1367
|
-
return `[${value.map(v => this.formatValue(v)).join(', ')}]`;
|
|
1368
|
-
if (typeof value === 'object') {
|
|
1369
|
-
try {
|
|
1370
|
-
return JSON.stringify(value);
|
|
1371
|
-
}
|
|
1372
|
-
catch {
|
|
1373
|
-
// Handle circular references
|
|
1374
|
-
return '[Circular Reference]';
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
return String(value);
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
/**
|
|
1381
|
-
* Global error message formatter instance
|
|
1382
|
-
*/
|
|
1383
|
-
const errorFormatter = new ErrorMessageFormatter();
|
|
1384
|
-
/**
|
|
1385
|
-
* Set global language
|
|
1386
|
-
*/
|
|
1387
|
-
function setValidationLanguage(language) {
|
|
1388
|
-
errorFormatter.setLanguage(language);
|
|
1389
|
-
}
|
|
1390
|
-
/**
|
|
1391
|
-
* Create validation error
|
|
1392
|
-
*/
|
|
1393
|
-
function createValidationError(field, value, constraint, customMessage, context) {
|
|
1394
|
-
const message = customMessage || errorFormatter.formatMessage(constraint, field, value, context);
|
|
1395
|
-
return {
|
|
1396
|
-
field,
|
|
1397
|
-
value,
|
|
1398
|
-
constraint,
|
|
1399
|
-
message,
|
|
1400
|
-
context
|
|
1401
|
-
};
|
|
1402
|
-
}
|
|
1403
|
-
/**
|
|
1404
|
-
* Create validation errors in batch
|
|
1405
|
-
*/
|
|
1406
|
-
function createValidationErrors(errors) {
|
|
1407
|
-
const validationErrors = errors.map(error => createValidationError(error.field, error.value, error.constraint, error.message, error.context));
|
|
1408
|
-
return new KoattyValidationError(validationErrors);
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
1432
|
/**
|
|
1412
1433
|
* Refactored decorator definitions - Using factory functions to eliminate duplication
|
|
1413
1434
|
* @author richen
|
|
@@ -1434,7 +1455,10 @@ const Lt = createParameterizedDecorator('Lt', (value, max) => helper__namespace.
|
|
|
1434
1455
|
const Lte = createParameterizedDecorator('Lte', (value, max) => helper__namespace.toNumber(value) <= max, 'must be less than or equal to $constraint1');
|
|
1435
1456
|
// 复杂验证装饰器(需要特殊处理)
|
|
1436
1457
|
function IsEmail(options, validationOptions) {
|
|
1437
|
-
|
|
1458
|
+
// Handle case where options is actually ValidationOptions (message only)
|
|
1459
|
+
const actualOptions = (options === null || options === void 0 ? void 0 : options.message) ? {} : options;
|
|
1460
|
+
const actualValidationOptions = (options === null || options === void 0 ? void 0 : options.message) ? options : validationOptions;
|
|
1461
|
+
return createParameterizedDecorator('IsEmail', (value) => classValidator.isEmail(value, actualOptions), 'must be a valid email')(actualValidationOptions);
|
|
1438
1462
|
}
|
|
1439
1463
|
function IsIP(version, validationOptions) {
|
|
1440
1464
|
return createParameterizedDecorator('IsIP', (value) => classValidator.isIP(value, version), 'must be a valid IP address')(validationOptions);
|