@nhtio/validation 1.20250804.0 → 1.20250814.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nhtio/validation",
3
- "version": "1.20250804.0",
3
+ "version": "1.20250814.0",
4
4
  "description": "A powerful schema description language and data validator",
5
5
  "keywords": [],
6
6
  "author": "Jak Giveon <jak@nht.io>",
@@ -1,6 +1,11 @@
1
- import type { Root } from 'joi';
1
+ import type { DateTime } from 'luxon';
2
+ import type { PhoneSchema } from './schemas/phone';
2
3
  import type { BigIntSchema } from './schemas/bigint';
3
4
  import type { DatetimeSchema } from './schemas/datetime';
5
+ import type { CountryOrUnknown } from '@nhtio/phone-object';
6
+ import type { Root, Reference, SchemaMap, SchemaLike } from 'joi';
7
+ import type { I18nCallback, SetI18nCallback } from './patches/i18n';
8
+ import type { AlternativesSchema, AnySchema, StringSchema, BinarySchema, NumberSchema, BooleanSchema, ObjectSchema, ArraySchema, DateSchema } from './schemas';
4
9
  /**
5
10
  * Extended Joi root interface that includes custom schema types for
6
11
  * additional validation scenarios.
@@ -20,9 +25,123 @@ import type { DatetimeSchema } from './schemas/datetime';
20
25
  *
21
26
  * @public
22
27
  */
23
- export interface ValidationRoot extends Root {
24
- bigint(): BigIntSchema;
25
- datetime(): DatetimeSchema;
28
+ export interface ValidationRoot extends Omit<Root, 'any' | 'string' | 'binary' | 'number' | 'bool' | 'boolean' | 'object' | 'array' | 'date' | 'alternatives' | 'alt'> {
29
+ /**
30
+ * Generates a schema object that matches any data type.
31
+ */
32
+ any<TSchema = any>(): AnySchema<TSchema>;
33
+ /**
34
+ * Generates a schema object that matches an array data type.
35
+ */
36
+ array<TSchema = any[]>(): ArraySchema<TSchema>;
37
+ /**
38
+ * Generates a schema object that matches a boolean data type (as well as the strings 'true', 'false', 'yes', and 'no'). Can also be called via boolean().
39
+ */
40
+ bool<TSchema = boolean>(): BooleanSchema<TSchema>;
41
+ /**
42
+ * Generates a schema object that matches a boolean data type (as well as the strings 'true', 'false', 'yes', and 'no'). Can also be called via bool().
43
+ */
44
+ boolean<TSchema = boolean>(): BooleanSchema<TSchema>;
45
+ /**
46
+ * Generates a schema object that matches a Buffer data type (as well as the strings which will be converted to Buffers).
47
+ */
48
+ binary<TSchema = Buffer>(): BinarySchema<TSchema>;
49
+ /**
50
+ * Generates a schema object that matches a date type (as well as a JavaScript date string or number of milliseconds).
51
+ */
52
+ date<TSchema = Date>(): DateSchema<TSchema>;
53
+ /**
54
+ * Generates a schema object that matches a number data type (as well as strings that can be converted to numbers).
55
+ */
56
+ number<TSchema = number>(): NumberSchema<TSchema>;
57
+ /**
58
+ * Generates a schema object that matches an object data type (as well as JSON strings that have been parsed into objects).
59
+ */
60
+ object<TSchema = any, IsStrict = false, T = TSchema>(schema?: SchemaMap<T, IsStrict>): ObjectSchema<TSchema>;
61
+ /**
62
+ * Generates a schema object that matches a string data type. Note that empty strings are not allowed by default and must be enabled with allow('').
63
+ */
64
+ string<TSchema = string>(): StringSchema<TSchema>;
65
+ /**
66
+ * Generates a type that will match one of the provided alternative schemas
67
+ */
68
+ alternatives<TSchema = any>(types: SchemaLike[]): AlternativesSchema<TSchema>;
69
+ alternatives<TSchema = any>(...types: SchemaLike[]): AlternativesSchema<TSchema>;
70
+ /**
71
+ * Alias for `alternatives`
72
+ */
73
+ alt<TSchema = any>(types: SchemaLike[]): AlternativesSchema<TSchema>;
74
+ alt<TSchema = any>(...types: SchemaLike[]): AlternativesSchema<TSchema>;
75
+ /**
76
+ * Generates a schema object that matches a BigInt data type.
77
+ */
78
+ bigint<TSchema = bigint>(): BigIntSchema<TSchema>;
79
+ /**
80
+ * Generates a schema object that matches a DateTime data type.
81
+ */
82
+ datetime<TSchema = DateTime>(): DatetimeSchema<TSchema>;
83
+ /**
84
+ * Generates a schema object that matches a phone number data type.
85
+ *
86
+ * @param country - Optional country code or reference for phone validation
87
+ */
88
+ phone<TSchema = string>(country?: CountryOrUnknown | Reference | null): PhoneSchema<TSchema>;
89
+ /**
90
+ * Sets a global internationalization callback that applies to all validator instances.
91
+ *
92
+ * This method sets a fallback translation function that will be used by the `$i18n` method
93
+ * when no instance-specific callback has been set via `$setI18n`. Once `$setI18n` is called
94
+ * on an instance, that instance will use its own callback instead of the global one.
95
+ *
96
+ * The global callback provides a convenient way to set default translations across your
97
+ * entire application while still allowing individual validator instances to override
98
+ * with their own translations when needed.
99
+ *
100
+ * @param callback - The I18nCallback function that will handle global message translation
101
+ * @returns The validator instance for chaining
102
+ *
103
+ * @example
104
+ * ```typescript
105
+ * // Set up global Spanish translations
106
+ * validator.$setGlobalI18n((term: string) => {
107
+ * return spanishTranslations[term] || term
108
+ * })
109
+ *
110
+ * // All validators will now use Spanish by default
111
+ * const schema1 = validator.string().min(5)
112
+ * const schema2 = validator.number().positive()
113
+ *
114
+ * // But you can still override for specific instances
115
+ * const germanSchema = validator.string().$setI18n(germanCallback)
116
+ * ```
117
+ */
118
+ $setI18n: SetI18nCallback<ValidationRoot>;
119
+ /**
120
+ * Clears the global internationalization callback.
121
+ *
122
+ * This method removes any previously set global i18n callback, causing the `$i18n` method
123
+ * to fall back to default English messages for validator instances that haven't had their
124
+ * own callback set via `$setI18n`.
125
+ *
126
+ * This is useful for testing scenarios, dynamic language switching, or memory cleanup
127
+ * when you no longer need global translations.
128
+ *
129
+ * @returns The validator instance for chaining
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * // Set up global translations
134
+ * validator.$setGlobalI18n(spanishCallback)
135
+ *
136
+ * // Later, clear them to return to default English
137
+ * validator.$clearGlobalI18n()
138
+ *
139
+ * // Now all validators use default English messages again
140
+ * const schema = validator.string().min(5) // Uses English messages
141
+ * ```
142
+ */
143
+ $clearI18n: () => ValidationRoot;
144
+ $i18n: I18nCallback;
26
145
  }
27
146
  /**
28
147
  * Extended Joi instance with custom schema types.
@@ -45,7 +164,6 @@ export interface ValidationRoot extends Root {
45
164
  * @public
46
165
  */
47
166
  export declare const validator: ValidationRoot;
48
- export type { BigIntSchema };
49
- export type { DatetimeSchema };
167
+ export type { BigIntSchema, DatetimeSchema, PhoneSchema, SetI18nCallback, I18nCallback };
50
168
  export type * from './schemas';
51
169
  export { encode, decode } from './utils';
@@ -0,0 +1,51 @@
1
+ import type { Root } from 'joi';
2
+ /**
3
+ * Callback function type for internationalization translation.
4
+ *
5
+ * This function is responsible for translating validation message keys into
6
+ * localized strings. It receives a message term (like 'string.min') and should
7
+ * return the translated message in the appropriate language.
8
+ *
9
+ * @param term - The message key to translate (e.g., 'string.base', 'number.min')
10
+ * @returns The translated message string, or the original term if translation fails
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const translateToSpanish: I18nCallback = (term: string) => {
15
+ * const translations = {
16
+ * 'string.base': 'debe ser una cadena de texto',
17
+ * 'number.min': 'debe ser mayor o igual a {{#limit}}'
18
+ * }
19
+ * return translations[term] || term
20
+ * }
21
+ * ```
22
+ */
23
+ export interface I18nCallback {
24
+ (term: string): string;
25
+ }
26
+ /**
27
+ * Callback function type for setting up internationalization.
28
+ *
29
+ * This function is used to configure the i18n system by providing a translation
30
+ * callback. Once called, it sets up the root validator instance to use the
31
+ * provided translation function for all validation messages.
32
+ *
33
+ * @param callback - The I18nCallback function that will handle message translation
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * // Set up Spanish translations
38
+ * validator.$setI18n((term: string) => {
39
+ * return spanishTranslations[term] || term
40
+ * })
41
+ *
42
+ * // Set up with external i18n library
43
+ * validator.$setI18n((term: string) => {
44
+ * return i18next.t(`validation.${term}`, { defaultValue: term })
45
+ * })
46
+ * ```
47
+ */
48
+ export interface SetI18nCallback<T = Root> {
49
+ (this: T, callback: I18nCallback): T;
50
+ }
51
+ export declare const i18n: (toPatch: Root) => Root;
@@ -1,5 +1,15 @@
1
1
  import type { AnySchema } from '../schemas';
2
2
  import type { ExtensionFactory, Reference } from 'joi';
3
+ export declare const messages: {
4
+ 'bigint.base': string;
5
+ 'bigint.greater': string;
6
+ 'bigint.less': string;
7
+ 'bigint.max': string;
8
+ 'bigint.min': string;
9
+ 'bigint.multiple': string;
10
+ 'bigint.negative': string;
11
+ 'bigint.positive': string;
12
+ };
3
13
  /**
4
14
  * A Joi extension that adds support for BigInt validation with comprehensive
5
15
  * comparison operations and type coercion.
@@ -4,6 +4,21 @@ import type { Tokens } from '../types';
4
4
  import type { AnySchema } from '../schemas';
5
5
  import type { ExtensionFactory, Reference } from 'joi';
6
6
  import type { Zone, LocaleOptions, DateObjectUnits, ZoneOptions, ToISOTimeOptions, ToISODateOptions, ToSQLOptions, ToRelativeOptions } from 'luxon';
7
+ export declare const messages: {
8
+ 'datetime.base': string;
9
+ 'datetime.exactly': string;
10
+ 'datetime.equals': string;
11
+ 'datetime.after': string;
12
+ 'datetime.greater': string;
13
+ 'datetime.before': string;
14
+ 'datetime.less': string;
15
+ 'datetime.afterOrEqual': string;
16
+ 'datetime.min': string;
17
+ 'datetime.beforeOrEqual': string;
18
+ 'datetime.max': string;
19
+ 'datetime.weekend': string;
20
+ 'datetime.weekday': string;
21
+ };
7
22
  /**
8
23
  * Types that can be parsed into a DateTime object.
9
24
  *
@@ -0,0 +1,199 @@
1
+ import type { AnySchema } from '../../index';
2
+ import type { CountryOrUnknown, PhoneTypes } from '@nhtio/phone-object';
3
+ import type { ExtensionFactory, Reference } from 'joi';
4
+ /**
5
+ * Phone number validation schema interface extending AnySchema.
6
+ * Provides methods for validating and formatting phone numbers with various constraints.
7
+ *
8
+ * @template TSchema - The schema type, defaults to string
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import Joi from 'joi'
13
+ * import { phone } from './phone'
14
+ *
15
+ * const extended = Joi.extend(phone)
16
+ * const schema = extended.phone().country('US').mobile()
17
+ *
18
+ * const result = schema.validate('+1234567890')
19
+ * ```
20
+ */
21
+ export interface PhoneSchema<TSchema = string> extends Omit<AnySchema<TSchema>, 'cast'> {
22
+ /**
23
+ * Sets the country context for phone number validation.
24
+ *
25
+ * @param country - Country code (ISO 3166-1 alpha-2), country name, Joi reference, or null
26
+ * @returns The schema instance for chaining
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * schema.country('US')
31
+ * schema.country('United States')
32
+ * schema.country(Joi.ref('countryField'))
33
+ * ```
34
+ */
35
+ country(country: CountryOrUnknown | Reference | null): this;
36
+ /**
37
+ * Sets the output format for the phone number.
38
+ *
39
+ * @param as - The desired output format
40
+ * @returns The schema instance for chaining
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * schema.format('international') // +1 234 567 8900
45
+ * schema.format('national') // (234) 567-8900
46
+ * schema.format('e164') // +12345678900
47
+ * ```
48
+ */
49
+ format(as: 'e164' | 'international' | 'national' | 'raw' | 'timezone' | 'type' | 'country'): this;
50
+ /**
51
+ * Validates that the phone number is a fixed line or fixed line/mobile number.
52
+ *
53
+ * @returns The schema instance for chaining
54
+ */
55
+ fixedLine(): this;
56
+ /**
57
+ * Validates that the phone number is a mobile or fixed line/mobile number.
58
+ *
59
+ * @returns The schema instance for chaining
60
+ */
61
+ mobile(): this;
62
+ /**
63
+ * Validates that the phone number is strictly a fixed line number only.
64
+ *
65
+ * @returns The schema instance for chaining
66
+ */
67
+ strictFixedLine(): this;
68
+ /**
69
+ * Validates that the phone number is strictly a mobile number only.
70
+ *
71
+ * @returns The schema instance for chaining
72
+ */
73
+ strictMobile(): this;
74
+ /**
75
+ * Validates that the phone number is either a fixed line or mobile number.
76
+ *
77
+ * @returns The schema instance for chaining
78
+ */
79
+ fixedLineOrMobile(): this;
80
+ /**
81
+ * Validates that the phone number is a toll-free number.
82
+ *
83
+ * @returns The schema instance for chaining
84
+ */
85
+ tollFree(): this;
86
+ /**
87
+ * Validates that the phone number is a premium rate number.
88
+ *
89
+ * @returns The schema instance for chaining
90
+ */
91
+ premiumRate(): this;
92
+ /**
93
+ * Validates that the phone number is a shared cost number.
94
+ *
95
+ * @returns The schema instance for chaining
96
+ */
97
+ sharedCost(): this;
98
+ /**
99
+ * Validates that the phone number is a VoIP number.
100
+ *
101
+ * @returns The schema instance for chaining
102
+ */
103
+ voip(): this;
104
+ /**
105
+ * Validates that the phone number is a personal number.
106
+ *
107
+ * @returns The schema instance for chaining
108
+ */
109
+ personalNumber(): this;
110
+ /**
111
+ * Validates that the phone number is a pager number.
112
+ *
113
+ * @returns The schema instance for chaining
114
+ */
115
+ pager(): this;
116
+ /**
117
+ * Validates that the phone number is a UAN (Universal Access Number).
118
+ *
119
+ * @returns The schema instance for chaining
120
+ */
121
+ uan(): this;
122
+ /**
123
+ * Validates that the phone number is a voicemail number.
124
+ *
125
+ * @returns The schema instance for chaining
126
+ */
127
+ voicemail(): this;
128
+ /**
129
+ * Validates that the phone number is of unknown type.
130
+ *
131
+ * @returns The schema instance for chaining
132
+ */
133
+ unknown(): this;
134
+ /**
135
+ * Validates that the phone number matches one of the specified types.
136
+ *
137
+ * @param types - Array of phone types to allow
138
+ * @returns The schema instance for chaining
139
+ *
140
+ * @example
141
+ * ```typescript
142
+ * schema.types('MOBILE', 'FIXED_LINE')
143
+ * ```
144
+ */
145
+ types(...types: PhoneTypes[]): this;
146
+ cast(to: 'number' | 'string' | 'object'): this;
147
+ }
148
+ export declare const messages: {
149
+ 'phone.base': string;
150
+ 'phone.invalid': string;
151
+ 'phone.fixedLine': string;
152
+ 'phone.mobile': string;
153
+ 'phone.strictFixedLine': string;
154
+ 'phone.strictMobile': string;
155
+ 'phone.fixedLineOrMobile': string;
156
+ 'phone.tollFree': string;
157
+ 'phone.premiumRate': string;
158
+ 'phone.sharedCost': string;
159
+ 'phone.voip': string;
160
+ 'phone.personalNumber': string;
161
+ 'phone.pager': string;
162
+ 'phone.uan': string;
163
+ 'phone.voicemail': string;
164
+ 'phone.unknown': string;
165
+ 'phone.types': string;
166
+ };
167
+ /**
168
+ * Joi extension factory for phone number validation.
169
+ * Creates a custom Joi schema type that validates phone numbers using the @nhtio/phone-object library.
170
+ *
171
+ * @param joi - The Joi instance to extend
172
+ * @returns The phone schema extension definition
173
+ *
174
+ * @example
175
+ * ```typescript
176
+ * import Joi from 'joi'
177
+ * import { phone } from './phone'
178
+ *
179
+ * const extended = Joi.extend(phone)
180
+ *
181
+ * // Basic phone validation
182
+ * const schema = extended.phone()
183
+ * schema.validate('+1234567890') // validates any phone number
184
+ *
185
+ * // Country-specific validation
186
+ * const usSchema = extended.phone().country('US')
187
+ * usSchema.validate('(555) 123-4567')
188
+ *
189
+ * // Type-specific validation
190
+ * const mobileSchema = extended.phone().mobile()
191
+ * mobileSchema.validate('+1234567890')
192
+ *
193
+ * // Format output
194
+ * const formattedSchema = extended.phone().format('international')
195
+ * const result = formattedSchema.validate('+1234567890')
196
+ * // result.value would be "+1 234 567 8900"
197
+ * ```
198
+ */
199
+ export declare const phone: ExtensionFactory;