@hy_ong/zod-kit 0.1.1 → 0.1.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/dist/index.cjs CHANGED
@@ -1291,35 +1291,31 @@ var validateIdType = (value, type) => {
1291
1291
  return pattern ? pattern.test(value) : false;
1292
1292
  };
1293
1293
  function id(required, options) {
1294
- const {
1295
- type = "auto",
1296
- minLength,
1297
- maxLength,
1298
- allowedTypes,
1299
- customRegex,
1300
- includes,
1301
- excludes,
1302
- startsWith,
1303
- endsWith,
1304
- caseSensitive = true,
1305
- transform,
1306
- defaultValue,
1307
- i18n
1308
- } = options ?? {};
1294
+ const { type = "auto", minLength, maxLength, allowedTypes, customRegex, includes, excludes, startsWith, endsWith, caseSensitive = true, transform, defaultValue, i18n } = options ?? {};
1309
1295
  const isRequired = required ?? false;
1310
- const actualDefaultValue = defaultValue ?? (isRequired ? "" : null);
1296
+ const isNumericType = type === "numeric";
1297
+ const actualDefaultValue = defaultValue !== void 0 ? defaultValue : isRequired ? isNumericType ? NaN : "" : null;
1311
1298
  const getMessage = (key, params) => {
1312
1299
  if (i18n) {
1313
1300
  const currentLocale2 = getLocale();
1314
1301
  const customMessages = i18n[currentLocale2];
1315
1302
  if (customMessages && customMessages[key]) {
1316
1303
  const template = customMessages[key];
1317
- return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "");
1304
+ return template.replace(/\$\{(\w+)}/g, (_match, k) => params?.[k] ?? "");
1318
1305
  }
1319
1306
  }
1320
1307
  return t(`common.id.${key}`, params);
1321
1308
  };
1322
- const preprocessFn = (val) => {
1309
+ const preprocessNumericFn = (val) => {
1310
+ if (val === "" || val === null || val === void 0) {
1311
+ if (isRequired && defaultValue === void 0) {
1312
+ return void 0;
1313
+ }
1314
+ return actualDefaultValue;
1315
+ }
1316
+ return Number(val);
1317
+ };
1318
+ const preprocessStringFn = (val) => {
1323
1319
  if (val === "" || val === null || val === void 0) {
1324
1320
  return actualDefaultValue;
1325
1321
  }
@@ -1329,7 +1325,30 @@ function id(required, options) {
1329
1325
  }
1330
1326
  return processed;
1331
1327
  };
1332
- const baseSchema = isRequired ? import_zod6.z.preprocess(preprocessFn, import_zod6.z.string()) : import_zod6.z.preprocess(preprocessFn, import_zod6.z.string().nullable());
1328
+ if (isNumericType) {
1329
+ const numericSchema = import_zod6.z.preprocess(preprocessNumericFn, import_zod6.z.any()).refine((val) => {
1330
+ if (!isRequired && val === null) return true;
1331
+ if (val === void 0 || isRequired && val === null) {
1332
+ throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("required"), path: [] }]);
1333
+ }
1334
+ if (typeof val !== "number" || isNaN(val)) {
1335
+ throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("numeric"), path: [] }]);
1336
+ }
1337
+ const strVal = String(val);
1338
+ if (!ID_PATTERNS.numeric.test(strVal)) {
1339
+ throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("numeric"), path: [] }]);
1340
+ }
1341
+ if (minLength !== void 0 && strVal.length < minLength) {
1342
+ throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("minLength", { minLength }), path: [] }]);
1343
+ }
1344
+ if (maxLength !== void 0 && strVal.length > maxLength) {
1345
+ throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("maxLength", { maxLength }), path: [] }]);
1346
+ }
1347
+ return true;
1348
+ });
1349
+ return numericSchema;
1350
+ }
1351
+ const baseSchema = isRequired ? import_zod6.z.preprocess(preprocessStringFn, import_zod6.z.string()) : import_zod6.z.preprocess(preprocessStringFn, import_zod6.z.string().nullable());
1333
1352
  const schema = baseSchema.refine((val) => {
1334
1353
  if (val === null) return true;
1335
1354
  if (isRequired && (val === "" || val === "null" || val === "undefined")) {
@@ -1355,7 +1374,7 @@ function id(required, options) {
1355
1374
  const typeNames = allowedTypes.join(", ");
1356
1375
  throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("invalid") + ` (allowed types: ${typeNames})`, path: [] }]);
1357
1376
  }
1358
- } else if (type !== "auto") {
1377
+ } else if (type && type !== "auto") {
1359
1378
  isValidId = validateIdType(val, type);
1360
1379
  if (!isValidId) {
1361
1380
  throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage(type) || getMessage("invalid"), path: [] }]);
@@ -1366,7 +1385,7 @@ function id(required, options) {
1366
1385
  throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("invalid"), path: [] }]);
1367
1386
  }
1368
1387
  }
1369
- } else if (val !== null && hasContentValidations && type !== "auto" && !customRegex) {
1388
+ } else if (val !== null && hasContentValidations && type && type !== "auto" && !customRegex) {
1370
1389
  if (allowedTypes && allowedTypes.length > 0) {
1371
1390
  const isValidType = allowedTypes.some((allowedType) => validateIdType(val, allowedType));
1372
1391
  if (!isValidType) {
package/dist/index.d.cts CHANGED
@@ -978,10 +978,11 @@ type IdType = "numeric" | "uuid" | "objectId" | "nanoid" | "snowflake" | "cuid"
978
978
  * Configuration options for ID validation
979
979
  *
980
980
  * @template IsRequired - Whether the field is required (affects return type)
981
+ * @template Type - The ID type being validated
981
982
  *
982
983
  * @interface IdOptions
983
984
  * @property {IsRequired} [required=true] - Whether the field is required
984
- * @property {IdType} [type="auto"] - Expected ID type or auto-detection
985
+ * @property {Type} [type="auto"] - Expected ID type or auto-detection
985
986
  * @property {number} [minLength] - Minimum length of ID
986
987
  * @property {number} [maxLength] - Maximum length of ID
987
988
  * @property {IdType[]} [allowedTypes] - Multiple allowed ID types (overrides type)
@@ -992,11 +993,11 @@ type IdType = "numeric" | "uuid" | "objectId" | "nanoid" | "snowflake" | "cuid"
992
993
  * @property {string} [endsWith] - String that ID must end with
993
994
  * @property {boolean} [caseSensitive=true] - Whether validation is case-sensitive
994
995
  * @property {Function} [transform] - Custom transformation function for ID
995
- * @property {string | null} [defaultValue] - Default value when input is empty
996
+ * @property {any} [defaultValue] - Default value when input is empty (string for string types, number for numeric)
996
997
  * @property {Record<Locale, IdMessages>} [i18n] - Custom error messages for different locales
997
998
  */
998
- type IdOptions<IsRequired extends boolean = true> = {
999
- type?: IdType;
999
+ type IdOptions<Type extends IdType | undefined = undefined> = {
1000
+ type?: Type;
1000
1001
  minLength?: number;
1001
1002
  maxLength?: number;
1002
1003
  allowedTypes?: IdType[];
@@ -1007,17 +1008,20 @@ type IdOptions<IsRequired extends boolean = true> = {
1007
1008
  endsWith?: string;
1008
1009
  caseSensitive?: boolean;
1009
1010
  transform?: (value: string) => string;
1010
- defaultValue?: IsRequired extends true ? string : string | null;
1011
+ defaultValue?: any;
1011
1012
  i18n?: Record<Locale, IdMessages>;
1012
1013
  };
1013
1014
  /**
1014
- * Type alias for ID validation schema based on required flag
1015
+ * Type alias for ID validation schema based on required flag and ID type
1015
1016
  *
1016
1017
  * @template IsRequired - Whether the field is required
1018
+ * @template IdType - The ID type being validated
1017
1019
  * @typedef IdSchema
1018
- * @description Returns ZodString if required, ZodNullable<ZodString> if optional
1020
+ * @description Returns appropriate Zod type based on required flag and ID type:
1021
+ * - numeric type: ZodNumber or ZodNullable<ZodNumber>
1022
+ * - other types: ZodString or ZodNullable<ZodString>
1019
1023
  */
1020
- type IdSchema<IsRequired extends boolean> = IsRequired extends true ? ZodString : ZodNullable<ZodString>;
1024
+ type IdSchema<IsRequired extends boolean, Type extends IdType | undefined = undefined> = Type extends "numeric" ? IsRequired extends true ? ZodNumber : ZodNullable<ZodNumber> : IsRequired extends true ? ZodString : ZodNullable<ZodString>;
1021
1025
  /**
1022
1026
  * Regular expression patterns for different ID formats
1023
1027
  *
@@ -1079,9 +1083,9 @@ declare const validateIdType: (value: string, type: IdType) => boolean;
1079
1083
  * Creates a Zod schema for ID validation with comprehensive format support
1080
1084
  *
1081
1085
  * @template IsRequired - Whether the field is required (affects return type)
1086
+ * @template Type - The ID type being validated (affects return type for numeric)
1082
1087
  * @param {IsRequired} [required=false] - Whether the field is required
1083
- * @param {Omit<ValidatorOptions<IsRequired>, 'required'>} [options] - Configuration options for validation
1084
- * @returns {IdSchema<IsRequired>} Zod schema for ID validation
1088
+ * @returns {IdSchema<IsRequired, Type>} Zod schema for ID validation
1085
1089
  *
1086
1090
  * @description
1087
1091
  * Creates a comprehensive ID validator with support for multiple ID formats,
@@ -1149,7 +1153,16 @@ declare const validateIdType: (value: string, type: IdType) => boolean;
1149
1153
  * @see {@link detectIdType} for auto-detection logic
1150
1154
  * @see {@link validateIdType} for type-specific validation
1151
1155
  */
1152
- declare function id<IsRequired extends boolean = false>(required?: IsRequired, options?: Omit<IdOptions<IsRequired>, 'required'>): IdSchema<IsRequired>;
1156
+ declare function id<IsRequired extends boolean = false>(required?: IsRequired): IdSchema<IsRequired, undefined>;
1157
+ declare function id<IsRequired extends boolean = false>(required: IsRequired, options: Omit<IdOptions<"numeric">, "required"> & {
1158
+ type: "numeric";
1159
+ }): IdSchema<IsRequired, "numeric">;
1160
+ declare function id<IsRequired extends boolean = false, Type extends Exclude<IdType, "numeric"> = Exclude<IdType, "numeric">>(required: IsRequired, options: Omit<IdOptions<Type>, "required"> & {
1161
+ type: Type;
1162
+ }): IdSchema<IsRequired, Type>;
1163
+ declare function id<IsRequired extends boolean = false>(required: IsRequired, options: Omit<IdOptions, "required"> & {
1164
+ type?: never;
1165
+ }): IdSchema<IsRequired, undefined>;
1153
1166
 
1154
1167
  /**
1155
1168
  * @fileoverview Number validator for Zod Kit
package/dist/index.d.ts CHANGED
@@ -978,10 +978,11 @@ type IdType = "numeric" | "uuid" | "objectId" | "nanoid" | "snowflake" | "cuid"
978
978
  * Configuration options for ID validation
979
979
  *
980
980
  * @template IsRequired - Whether the field is required (affects return type)
981
+ * @template Type - The ID type being validated
981
982
  *
982
983
  * @interface IdOptions
983
984
  * @property {IsRequired} [required=true] - Whether the field is required
984
- * @property {IdType} [type="auto"] - Expected ID type or auto-detection
985
+ * @property {Type} [type="auto"] - Expected ID type or auto-detection
985
986
  * @property {number} [minLength] - Minimum length of ID
986
987
  * @property {number} [maxLength] - Maximum length of ID
987
988
  * @property {IdType[]} [allowedTypes] - Multiple allowed ID types (overrides type)
@@ -992,11 +993,11 @@ type IdType = "numeric" | "uuid" | "objectId" | "nanoid" | "snowflake" | "cuid"
992
993
  * @property {string} [endsWith] - String that ID must end with
993
994
  * @property {boolean} [caseSensitive=true] - Whether validation is case-sensitive
994
995
  * @property {Function} [transform] - Custom transformation function for ID
995
- * @property {string | null} [defaultValue] - Default value when input is empty
996
+ * @property {any} [defaultValue] - Default value when input is empty (string for string types, number for numeric)
996
997
  * @property {Record<Locale, IdMessages>} [i18n] - Custom error messages for different locales
997
998
  */
998
- type IdOptions<IsRequired extends boolean = true> = {
999
- type?: IdType;
999
+ type IdOptions<Type extends IdType | undefined = undefined> = {
1000
+ type?: Type;
1000
1001
  minLength?: number;
1001
1002
  maxLength?: number;
1002
1003
  allowedTypes?: IdType[];
@@ -1007,17 +1008,20 @@ type IdOptions<IsRequired extends boolean = true> = {
1007
1008
  endsWith?: string;
1008
1009
  caseSensitive?: boolean;
1009
1010
  transform?: (value: string) => string;
1010
- defaultValue?: IsRequired extends true ? string : string | null;
1011
+ defaultValue?: any;
1011
1012
  i18n?: Record<Locale, IdMessages>;
1012
1013
  };
1013
1014
  /**
1014
- * Type alias for ID validation schema based on required flag
1015
+ * Type alias for ID validation schema based on required flag and ID type
1015
1016
  *
1016
1017
  * @template IsRequired - Whether the field is required
1018
+ * @template IdType - The ID type being validated
1017
1019
  * @typedef IdSchema
1018
- * @description Returns ZodString if required, ZodNullable<ZodString> if optional
1020
+ * @description Returns appropriate Zod type based on required flag and ID type:
1021
+ * - numeric type: ZodNumber or ZodNullable<ZodNumber>
1022
+ * - other types: ZodString or ZodNullable<ZodString>
1019
1023
  */
1020
- type IdSchema<IsRequired extends boolean> = IsRequired extends true ? ZodString : ZodNullable<ZodString>;
1024
+ type IdSchema<IsRequired extends boolean, Type extends IdType | undefined = undefined> = Type extends "numeric" ? IsRequired extends true ? ZodNumber : ZodNullable<ZodNumber> : IsRequired extends true ? ZodString : ZodNullable<ZodString>;
1021
1025
  /**
1022
1026
  * Regular expression patterns for different ID formats
1023
1027
  *
@@ -1079,9 +1083,9 @@ declare const validateIdType: (value: string, type: IdType) => boolean;
1079
1083
  * Creates a Zod schema for ID validation with comprehensive format support
1080
1084
  *
1081
1085
  * @template IsRequired - Whether the field is required (affects return type)
1086
+ * @template Type - The ID type being validated (affects return type for numeric)
1082
1087
  * @param {IsRequired} [required=false] - Whether the field is required
1083
- * @param {Omit<ValidatorOptions<IsRequired>, 'required'>} [options] - Configuration options for validation
1084
- * @returns {IdSchema<IsRequired>} Zod schema for ID validation
1088
+ * @returns {IdSchema<IsRequired, Type>} Zod schema for ID validation
1085
1089
  *
1086
1090
  * @description
1087
1091
  * Creates a comprehensive ID validator with support for multiple ID formats,
@@ -1149,7 +1153,16 @@ declare const validateIdType: (value: string, type: IdType) => boolean;
1149
1153
  * @see {@link detectIdType} for auto-detection logic
1150
1154
  * @see {@link validateIdType} for type-specific validation
1151
1155
  */
1152
- declare function id<IsRequired extends boolean = false>(required?: IsRequired, options?: Omit<IdOptions<IsRequired>, 'required'>): IdSchema<IsRequired>;
1156
+ declare function id<IsRequired extends boolean = false>(required?: IsRequired): IdSchema<IsRequired, undefined>;
1157
+ declare function id<IsRequired extends boolean = false>(required: IsRequired, options: Omit<IdOptions<"numeric">, "required"> & {
1158
+ type: "numeric";
1159
+ }): IdSchema<IsRequired, "numeric">;
1160
+ declare function id<IsRequired extends boolean = false, Type extends Exclude<IdType, "numeric"> = Exclude<IdType, "numeric">>(required: IsRequired, options: Omit<IdOptions<Type>, "required"> & {
1161
+ type: Type;
1162
+ }): IdSchema<IsRequired, Type>;
1163
+ declare function id<IsRequired extends boolean = false>(required: IsRequired, options: Omit<IdOptions, "required"> & {
1164
+ type?: never;
1165
+ }): IdSchema<IsRequired, undefined>;
1153
1166
 
1154
1167
  /**
1155
1168
  * @fileoverview Number validator for Zod Kit
package/dist/index.js CHANGED
@@ -1213,35 +1213,31 @@ var validateIdType = (value, type) => {
1213
1213
  return pattern ? pattern.test(value) : false;
1214
1214
  };
1215
1215
  function id(required, options) {
1216
- const {
1217
- type = "auto",
1218
- minLength,
1219
- maxLength,
1220
- allowedTypes,
1221
- customRegex,
1222
- includes,
1223
- excludes,
1224
- startsWith,
1225
- endsWith,
1226
- caseSensitive = true,
1227
- transform,
1228
- defaultValue,
1229
- i18n
1230
- } = options ?? {};
1216
+ const { type = "auto", minLength, maxLength, allowedTypes, customRegex, includes, excludes, startsWith, endsWith, caseSensitive = true, transform, defaultValue, i18n } = options ?? {};
1231
1217
  const isRequired = required ?? false;
1232
- const actualDefaultValue = defaultValue ?? (isRequired ? "" : null);
1218
+ const isNumericType = type === "numeric";
1219
+ const actualDefaultValue = defaultValue !== void 0 ? defaultValue : isRequired ? isNumericType ? NaN : "" : null;
1233
1220
  const getMessage = (key, params) => {
1234
1221
  if (i18n) {
1235
1222
  const currentLocale2 = getLocale();
1236
1223
  const customMessages = i18n[currentLocale2];
1237
1224
  if (customMessages && customMessages[key]) {
1238
1225
  const template = customMessages[key];
1239
- return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "");
1226
+ return template.replace(/\$\{(\w+)}/g, (_match, k) => params?.[k] ?? "");
1240
1227
  }
1241
1228
  }
1242
1229
  return t(`common.id.${key}`, params);
1243
1230
  };
1244
- const preprocessFn = (val) => {
1231
+ const preprocessNumericFn = (val) => {
1232
+ if (val === "" || val === null || val === void 0) {
1233
+ if (isRequired && defaultValue === void 0) {
1234
+ return void 0;
1235
+ }
1236
+ return actualDefaultValue;
1237
+ }
1238
+ return Number(val);
1239
+ };
1240
+ const preprocessStringFn = (val) => {
1245
1241
  if (val === "" || val === null || val === void 0) {
1246
1242
  return actualDefaultValue;
1247
1243
  }
@@ -1251,7 +1247,30 @@ function id(required, options) {
1251
1247
  }
1252
1248
  return processed;
1253
1249
  };
1254
- const baseSchema = isRequired ? z6.preprocess(preprocessFn, z6.string()) : z6.preprocess(preprocessFn, z6.string().nullable());
1250
+ if (isNumericType) {
1251
+ const numericSchema = z6.preprocess(preprocessNumericFn, z6.any()).refine((val) => {
1252
+ if (!isRequired && val === null) return true;
1253
+ if (val === void 0 || isRequired && val === null) {
1254
+ throw new z6.ZodError([{ code: "custom", message: getMessage("required"), path: [] }]);
1255
+ }
1256
+ if (typeof val !== "number" || isNaN(val)) {
1257
+ throw new z6.ZodError([{ code: "custom", message: getMessage("numeric"), path: [] }]);
1258
+ }
1259
+ const strVal = String(val);
1260
+ if (!ID_PATTERNS.numeric.test(strVal)) {
1261
+ throw new z6.ZodError([{ code: "custom", message: getMessage("numeric"), path: [] }]);
1262
+ }
1263
+ if (minLength !== void 0 && strVal.length < minLength) {
1264
+ throw new z6.ZodError([{ code: "custom", message: getMessage("minLength", { minLength }), path: [] }]);
1265
+ }
1266
+ if (maxLength !== void 0 && strVal.length > maxLength) {
1267
+ throw new z6.ZodError([{ code: "custom", message: getMessage("maxLength", { maxLength }), path: [] }]);
1268
+ }
1269
+ return true;
1270
+ });
1271
+ return numericSchema;
1272
+ }
1273
+ const baseSchema = isRequired ? z6.preprocess(preprocessStringFn, z6.string()) : z6.preprocess(preprocessStringFn, z6.string().nullable());
1255
1274
  const schema = baseSchema.refine((val) => {
1256
1275
  if (val === null) return true;
1257
1276
  if (isRequired && (val === "" || val === "null" || val === "undefined")) {
@@ -1277,7 +1296,7 @@ function id(required, options) {
1277
1296
  const typeNames = allowedTypes.join(", ");
1278
1297
  throw new z6.ZodError([{ code: "custom", message: getMessage("invalid") + ` (allowed types: ${typeNames})`, path: [] }]);
1279
1298
  }
1280
- } else if (type !== "auto") {
1299
+ } else if (type && type !== "auto") {
1281
1300
  isValidId = validateIdType(val, type);
1282
1301
  if (!isValidId) {
1283
1302
  throw new z6.ZodError([{ code: "custom", message: getMessage(type) || getMessage("invalid"), path: [] }]);
@@ -1288,7 +1307,7 @@ function id(required, options) {
1288
1307
  throw new z6.ZodError([{ code: "custom", message: getMessage("invalid"), path: [] }]);
1289
1308
  }
1290
1309
  }
1291
- } else if (val !== null && hasContentValidations && type !== "auto" && !customRegex) {
1310
+ } else if (val !== null && hasContentValidations && type && type !== "auto" && !customRegex) {
1292
1311
  if (allowedTypes && allowedTypes.length > 0) {
1293
1312
  const isValidType = allowedTypes.some((allowedType) => validateIdType(val, allowedType));
1294
1313
  if (!isValidType) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hy_ong/zod-kit",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "A comprehensive TypeScript library providing pre-built Zod validation schemas with full internationalization support for common data types and Taiwan-specific formats",
5
5
  "keywords": [
6
6
  "zod",
@@ -238,38 +238,44 @@ export function date<IsRequired extends boolean = false>(required?: IsRequired,
238
238
 
239
239
  const baseSchema = isRequired ? z.preprocess(preprocessFn, z.string()) : z.preprocess(preprocessFn, z.string().nullable())
240
240
 
241
- const schema = baseSchema.refine((val) => {
242
- if (val === null) return true
241
+ const schema = baseSchema.superRefine((val, ctx) => {
242
+ if (val === null) return
243
243
 
244
244
  // Required check
245
245
  if (isRequired && (val === "" || val === "null" || val === "undefined")) {
246
- throw new z.ZodError([{ code: "custom", message: getMessage("required"), path: [] }])
246
+ ctx.addIssue({ code: "custom", message: getMessage("required") })
247
+ return
247
248
  }
248
249
 
249
250
  // Format validation
250
251
  if (val !== null && !dayjs(val, format, true).isValid()) {
251
- throw new z.ZodError([{ code: "custom", message: getMessage("format", { format }), path: [] }])
252
+ ctx.addIssue({ code: "custom", message: getMessage("format", { format }) })
253
+ return
252
254
  }
253
255
 
254
256
  const dateObj = dayjs(val, format)
255
257
 
256
258
  // Range checks
257
259
  if (val !== null && min !== undefined && !dateObj.isSameOrAfter(dayjs(min, format))) {
258
- throw new z.ZodError([{ code: "custom", message: getMessage("min", { min }), path: [] }])
260
+ ctx.addIssue({ code: "custom", message: getMessage("min", { min }) })
261
+ return
259
262
  }
260
263
  if (val !== null && max !== undefined && !dateObj.isSameOrBefore(dayjs(max, format))) {
261
- throw new z.ZodError([{ code: "custom", message: getMessage("max", { max }), path: [] }])
264
+ ctx.addIssue({ code: "custom", message: getMessage("max", { max }) })
265
+ return
262
266
  }
263
267
 
264
268
  // String content checks
265
269
  if (val !== null && includes !== undefined && !val.includes(includes)) {
266
- throw new z.ZodError([{ code: "custom", message: getMessage("includes", { includes }), path: [] }])
270
+ ctx.addIssue({ code: "custom", message: getMessage("includes", { includes }) })
271
+ return
267
272
  }
268
273
  if (val !== null && excludes !== undefined) {
269
274
  const excludeList = Array.isArray(excludes) ? excludes : [excludes]
270
275
  for (const exclude of excludeList) {
271
276
  if (val.includes(exclude)) {
272
- throw new z.ZodError([{ code: "custom", message: getMessage("excludes", { excludes: exclude }), path: [] }])
277
+ ctx.addIssue({ code: "custom", message: getMessage("excludes", { excludes: exclude }) })
278
+ return
273
279
  }
274
280
  }
275
281
  }
@@ -279,27 +285,31 @@ export function date<IsRequired extends boolean = false>(required?: IsRequired,
279
285
  const targetDate = dateObj.startOf('day')
280
286
 
281
287
  if (val !== null && mustBePast && !targetDate.isBefore(today)) {
282
- throw new z.ZodError([{ code: "custom", message: getMessage("past"), path: [] }])
288
+ ctx.addIssue({ code: "custom", message: getMessage("past") })
289
+ return
283
290
  }
284
291
  if (val !== null && mustBeFuture && !targetDate.isAfter(today)) {
285
- throw new z.ZodError([{ code: "custom", message: getMessage("future"), path: [] }])
292
+ ctx.addIssue({ code: "custom", message: getMessage("future") })
293
+ return
286
294
  }
287
295
  if (val !== null && mustBeToday && !targetDate.isSame(today)) {
288
- throw new z.ZodError([{ code: "custom", message: getMessage("today"), path: [] }])
296
+ ctx.addIssue({ code: "custom", message: getMessage("today") })
297
+ return
289
298
  }
290
299
  if (val !== null && mustNotBeToday && targetDate.isSame(today)) {
291
- throw new z.ZodError([{ code: "custom", message: getMessage("notToday"), path: [] }])
300
+ ctx.addIssue({ code: "custom", message: getMessage("notToday") })
301
+ return
292
302
  }
293
303
 
294
304
  // Weekday/weekend validations
295
305
  if (val !== null && weekdaysOnly && (dateObj.day() === 0 || dateObj.day() === 6)) {
296
- throw new z.ZodError([{ code: "custom", message: getMessage("weekday"), path: [] }])
306
+ ctx.addIssue({ code: "custom", message: getMessage("weekday") })
307
+ return
297
308
  }
298
309
  if (val !== null && weekendsOnly && dateObj.day() !== 0 && dateObj.day() !== 6) {
299
- throw new z.ZodError([{ code: "custom", message: getMessage("weekend"), path: [] }])
310
+ ctx.addIssue({ code: "custom", message: getMessage("weekend") })
311
+ return
300
312
  }
301
-
302
- return true
303
313
  })
304
314
 
305
315
  return schema as unknown as DateSchema<IsRequired>