0
# References and Expressions
1
2
Dynamic validation system supporting field references, context access, and template expressions for advanced validation scenarios.
3
4
## Capabilities
5
6
### Reference Function
7
8
Creates references to other fields or context values for dynamic validation.
9
10
```typescript { .api }
11
/**
12
* Creates reference to another field for dynamic validation
13
* @param key - Reference key (field path or context path)
14
* @param options - Optional reference configuration
15
* @returns Reference object for dynamic value access
16
*/
17
function ref(key: string, options?: ReferenceOptions): Reference;
18
19
interface ReferenceOptions {
20
// Separator for key path parsing (default: '.')
21
separator?: string;
22
23
// Context options
24
contextPrefix?: string; // Prefix for context references (default: '$')
25
26
// Path options
27
ancestor?: number; // Number of parent levels to traverse
28
prefix?: {
29
global?: string; // Global context prefix (default: '/')
30
local?: string; // Local context prefix (default: '#')
31
root?: string; // Root value prefix (default: '#')
32
};
33
34
// Rendering options
35
render?: boolean; // Enable template rendering (default: true)
36
37
// Adjustment function
38
adjust?: (value: any) => any; // Value adjustment function
39
40
// Mapping function
41
map?: Array<[any, any]> | Map<any, any>; // Value mapping
42
43
// In-references
44
in?: boolean; // Enable in-reference mode
45
}
46
47
interface Reference {
48
readonly isContext: boolean; // True if reference points to context
49
readonly isGlobal: boolean; // True if reference is global
50
readonly key: string; // Reference key
51
readonly path: string[]; // Parsed key path
52
readonly ancestor: number; // Ancestor level count
53
readonly prefix: string; // Reference prefix type
54
readonly root: string; // Root identifier
55
readonly display: string; // Display representation
56
readonly type: string; // Reference type ('value' | 'context' | 'global')
57
}
58
```
59
60
**Usage Examples:**
61
62
```javascript
63
const Joi = require('joi');
64
65
// Basic field reference
66
const schema = Joi.object({
67
password: Joi.string().min(8),
68
confirmPassword: Joi.string().valid(Joi.ref('password'))
69
});
70
71
// Context reference
72
const contextSchema = Joi.object({
73
minValue: Joi.number().min(Joi.ref('$minAllowed'))
74
});
75
76
const { error, value } = contextSchema.validate(
77
{ minValue: 5 },
78
{ context: { minAllowed: 10 } }
79
);
80
81
// Nested field reference
82
const nestedSchema = Joi.object({
83
user: Joi.object({
84
name: Joi.string(),
85
email: Joi.string().email()
86
}),
87
contact: Joi.object({
88
primaryEmail: Joi.string().valid(Joi.ref('..user.email'))
89
})
90
});
91
92
// Reference with ancestor traversal
93
const hierarchySchema = Joi.object({
94
level1: Joi.object({
95
value: Joi.string(),
96
level2: Joi.object({
97
compare: Joi.string().valid(Joi.ref('value', { ancestor: 1 }))
98
})
99
})
100
});
101
102
// Reference with custom separator
103
const customRefSchema = Joi.object({
104
'field/name': Joi.string(),
105
compare: Joi.string().valid(Joi.ref('field/name', { separator: '/' }))
106
});
107
```
108
109
### In Reference Function
110
111
Creates array references for rule matching and validation.
112
113
```typescript { .api }
114
/**
115
* Creates array reference for rule matching
116
* @param ref - Reference key or Reference object
117
* @param options - Optional reference configuration
118
* @returns Reference configured for array matching
119
*/
120
function in(ref: string | Reference, options?: ReferenceOptions): Reference;
121
```
122
123
**Usage Examples:**
124
125
```javascript
126
// Array membership validation
127
const membershipSchema = Joi.object({
128
allowedValues: Joi.array().items(Joi.string()),
129
selectedValue: Joi.string().valid(Joi.in('allowedValues'))
130
});
131
132
const { error, value } = membershipSchema.validate({
133
allowedValues: ['red', 'green', 'blue'],
134
selectedValue: 'red' // Valid - 'red' is in allowedValues array
135
});
136
137
// Dynamic validation based on array context
138
const dynamicSchema = Joi.object({
139
category: Joi.string().valid(Joi.in('$availableCategories'))
140
});
141
142
const contextValidation = dynamicSchema.validate(
143
{ category: 'electronics' },
144
{
145
context: {
146
availableCategories: ['electronics', 'clothing', 'books']
147
}
148
}
149
);
150
```
151
152
### Expression Function
153
154
Creates template expressions for dynamic content generation and validation.
155
156
```typescript { .api }
157
/**
158
* Creates template expressions with dynamic placeholders
159
* @param template - Template string with placeholder syntax
160
* @param options - Optional template configuration
161
* @returns Template object for dynamic rendering
162
*/
163
function expression(template: string, options?: TemplateOptions): Template;
164
165
// Alias for expression function
166
const x: typeof expression;
167
168
interface TemplateOptions {
169
// Custom functions for template rendering
170
functions?: Record<string, Function>;
171
172
// Variable references
173
reference?: boolean; // Enable reference resolution (default: true)
174
}
175
176
interface Template {
177
readonly isTemplate: boolean; // Always true for template objects
178
readonly source: string; // Original template string
179
180
/**
181
* Renders template with provided context
182
* @param context - Rendering context with variables
183
* @param prefs - Optional preferences
184
* @param local - Local context variables
185
* @param options - Rendering options
186
* @returns Rendered string
187
*/
188
render(
189
context: any,
190
prefs?: any,
191
local?: any,
192
options?: any
193
): string;
194
}
195
```
196
197
**Usage Examples:**
198
199
```javascript
200
// Basic template expression
201
const messageTemplate = Joi.expression('Hello {#name}, you are {#age} years old');
202
203
// Custom error messages with templates
204
const customSchema = Joi.string()
205
.min(3)
206
.message(Joi.expression('Field {#label} must be at least {#limit} characters, got {#value}'));
207
208
// Dynamic validation with templates
209
const dynamicValidation = Joi.object({
210
name: Joi.string().required(),
211
greeting: Joi.string().valid(Joi.expression('Hello {#name}'))
212
});
213
214
// Template with functions
215
const advancedTemplate = Joi.expression('User {#name|uppercase} has {#posts|length} posts', {
216
functions: {
217
uppercase: (value) => value.toUpperCase(),
218
length: (array) => array ? array.length : 0
219
}
220
});
221
222
// Using x alias
223
const shortTemplate = Joi.x('Welcome {#user.name}!');
224
```
225
226
### Reference Utilities
227
228
Utility functions for working with references and templates.
229
230
```typescript { .api }
231
/**
232
* Checks if value is a reference object
233
* @param ref - Value to check
234
* @returns True if value is Reference object
235
*/
236
function isRef(ref: any): ref is Reference;
237
238
/**
239
* Checks if value is a template expression
240
* @param expression - Value to check
241
* @returns True if value is Template object
242
*/
243
function isExpression(expression: any): expression is Template;
244
```
245
246
**Usage Examples:**
247
248
```javascript
249
const ref = Joi.ref('field');
250
const template = Joi.expression('Hello {#name}');
251
const string = 'regular string';
252
253
console.log(Joi.isRef(ref)); // true
254
console.log(Joi.isRef(template)); // false
255
console.log(Joi.isRef(string)); // false
256
257
console.log(Joi.isExpression(template)); // true
258
console.log(Joi.isExpression(ref)); // false
259
console.log(Joi.isExpression(string)); // false
260
```
261
262
## Advanced Reference Patterns
263
264
### Conditional Validation with References
265
266
```javascript
267
const conditionalSchema = Joi.object({
268
type: Joi.string().valid('user', 'admin'),
269
permissions: Joi.array()
270
.when('type', {
271
is: 'admin',
272
then: Joi.array().min(1),
273
otherwise: Joi.array().max(0)
274
})
275
});
276
```
277
278
### Complex Object Relationships
279
280
```javascript
281
const relationshipSchema = Joi.object({
282
startDate: Joi.date(),
283
endDate: Joi.date().greater(Joi.ref('startDate')),
284
duration: Joi.number().when('startDate', {
285
is: Joi.exist(),
286
then: Joi.number().min(1),
287
otherwise: Joi.forbidden()
288
})
289
});
290
```
291
292
### Dynamic Array Validation
293
294
```javascript
295
const dynamicArraySchema = Joi.object({
296
maxItems: Joi.number().integer().min(1),
297
items: Joi.array().max(Joi.ref('maxItems')),
298
selectedItems: Joi.array()
299
.items(Joi.string().valid(Joi.in('items')))
300
.unique()
301
});
302
```
303
304
### Template-Based Error Messages
305
306
```javascript
307
const customErrorSchema = Joi.object({
308
username: Joi.string()
309
.min(3)
310
.max(20)
311
.messages({
312
'string.min': Joi.expression('Username {#label} must be at least {#limit} characters'),
313
'string.max': Joi.expression('Username {#label} cannot exceed {#limit} characters')
314
}),
315
316
email: Joi.string()
317
.email()
318
.message(Joi.expression('Please provide a valid email address for {#label}'))
319
});
320
```
321
322
## Context-Aware Validation
323
324
### Global Context References
325
326
```javascript
327
const globalContextSchema = Joi.object({
328
userLevel: Joi.string().valid(Joi.ref('/user.level')),
329
maxUpload: Joi.number().max(Joi.ref('/limits.upload'))
330
});
331
332
// Validation with global context
333
const result = globalContextSchema.validate(data, {
334
context: {
335
'/': {
336
user: { level: 'premium' },
337
limits: { upload: 1000000 }
338
}
339
}
340
});
341
```
342
343
### Local Context References
344
345
```javascript
346
const localContextSchema = Joi.object({
347
priority: Joi.string().valid(Joi.ref('#priorities')),
348
category: Joi.string().valid(Joi.ref('#categories'))
349
});
350
351
// Local context validation
352
const localResult = localContextSchema.validate(data, {
353
context: {
354
priorities: ['low', 'medium', 'high'],
355
categories: ['bug', 'feature', 'enhancement']
356
}
357
});
358
```
359
360
## Template Functions
361
362
### Built-in Template Functions
363
364
```javascript
365
// String manipulation functions
366
const stringTemplate = Joi.expression('{#name|lowercase|trim}');
367
368
// Array functions
369
const arrayTemplate = Joi.expression('Found {#items|length} items');
370
371
// Date functions
372
const dateTemplate = Joi.expression('Created on {#createdAt|date("YYYY-MM-DD")}');
373
374
// Custom functions
375
const customTemplate = Joi.expression('{#value|multiply(2)|format}', {
376
functions: {
377
multiply: (value, factor) => value * factor,
378
format: (value) => `$${value.toFixed(2)}`
379
}
380
});
381
```