Object schema validation library for JavaScript with comprehensive validation capabilities
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Helper functions for type checking, introspection, and working with joi objects and errors.
Functions for identifying joi objects and their types.
/**
* Checks if value is a joi schema object
* @param schema - Value to check
* @param options - Optional checking options
* @returns True if value is a joi schema
*/
function isSchema(schema: any, options?: any): schema is Schema;
/**
* Checks if value is a reference object
* @param ref - Value to check
* @returns True if value is Reference object
*/
function isRef(ref: any): ref is Reference;
/**
* Checks if value is a template expression
* @param expression - Value to check
* @returns True if value is Template object
*/
function isExpression(expression: any): expression is Template;
/**
* Checks if error is a ValidationError instance
* @param error - Error object to check
* @returns True if error is ValidationError
*/
function isError(error: any): error is ValidationError;Usage Examples:
const Joi = require('joi');
const schema = Joi.string().min(3);
const ref = Joi.ref('field');
const template = Joi.expression('Hello {#name}');
const error = new Joi.ValidationError('Test error', [], null);
const regularString = 'not a joi object';
// Type checking
console.log(Joi.isSchema(schema)); // true
console.log(Joi.isSchema(ref)); // false
console.log(Joi.isSchema(regularString)); // false
console.log(Joi.isRef(ref)); // true
console.log(Joi.isRef(schema)); // false
console.log(Joi.isExpression(template)); // true
console.log(Joi.isExpression(schema)); // false
console.log(Joi.isError(error)); // true
console.log(Joi.isError(new Error())); // false
// Conditional logic based on type checking
function processJoiValue(value) {
if (Joi.isSchema(value)) {
return value.describe();
} else if (Joi.isRef(value)) {
return `Reference to: ${value.key}`;
} else if (Joi.isExpression(value)) {
return `Template: ${value.source}`;
} else {
return 'Not a joi object';
}
}Functions for examining and working with schema instances.
/**
* Returns object containing all available schema types
* @returns Record mapping type names to schema instances
*/
function types(): Record<string, Schema>;Usage Examples:
// Get all available schema types
const allTypes = Joi.types();
console.log(Object.keys(allTypes));
// ['any', 'array', 'boolean', 'date', 'function', 'link',
// 'number', 'object', 'string', 'symbol', 'alternatives',
// 'binary', 'alt', 'bool', 'func']
// Access specific schema types
const stringSchema = allTypes.string;
const numberSchema = allTypes.number;
// Use in dynamic schema creation
function createSchemaByType(type, options = {}) {
const availableTypes = Joi.types();
if (availableTypes[type]) {
return availableTypes[type];
}
throw new Error(`Unknown schema type: ${type}`);
}
const dynamicSchema = createSchemaByType('string').min(5);Global constants and configuration objects.
/**
* Library version string
*/
const version: string;
/**
* Cache configuration provider
*/
const cache: CacheProvider;
/**
* Special symbol for resetting allowed values
*/
const override: symbol;
interface CacheProvider {
provision(options?: CacheOptions): Cache;
}
interface CacheOptions {
max?: number; // Maximum cache entries
maxAge?: number; // Maximum age in milliseconds
}
interface Cache {
get(key: string): any;
set(key: string, value: any, ttl?: number): void;
has(key: string): boolean;
clear(): void;
}Usage Examples:
// Check joi version
console.log(`Using joi version: ${Joi.version}`);
// Use override symbol to reset allowed values
const schema = Joi.string()
.valid('a', 'b', 'c')
.valid(Joi.override, 'x', 'y', 'z'); // Replaces previous valid values
// Custom cache configuration
const customCache = Joi.cache.provision({
max: 1000, // Maximum 1000 cached schemas
maxAge: 300000 // Cache for 5 minutes
});
// Use cache with schema validation
const cachedSchema = Joi.string().cache(customCache);Error class specifically for joi validation failures.
/**
* Joi validation error constructor
*/
class ValidationError extends Error {
name: 'ValidationError';
isJoi: true;
details: ValidationErrorItem[];
_original: any;
/**
* Creates a new ValidationError
* @param message - Error message
* @param details - Array of error details
* @param original - Original input value
*/
constructor(message: string, details: ValidationErrorItem[], original: any);
/**
* Returns formatted error message with annotations
* @param options - Formatting options
* @returns Annotated error string
*/
annotate(options?: AnnotateOptions): string;
/**
* Static method to check if error is ValidationError
* @param error - Error to check
* @returns True if error is ValidationError instance
*/
static isError(error: any): error is ValidationError;
}
interface ValidationErrorItem {
message: string; // Error message
path: (string | number)[]; // Path to error location
type: string; // Error type identifier
context?: { // Error context
key?: string; // Field key
label?: string; // Field label
value?: any; // Invalid value
limit?: any; // Constraint limit
encoding?: string; // Expected encoding
[key: string]: any; // Additional context
};
}
interface AnnotateOptions {
stripColors?: boolean; // Remove color codes
}Usage Examples:
// Create custom ValidationError
const customError = new Joi.ValidationError(
'Custom validation failed',
[{
message: 'Value is invalid',
path: ['field'],
type: 'custom.invalid',
context: { key: 'field', value: 'bad-value' }
}],
{ field: 'bad-value' }
);
// Check error type
console.log(Joi.ValidationError.isError(customError)); // true
console.log(customError.isJoi); // true
// Use in validation
try {
const result = schema.validate(invalidData);
if (result.error) {
throw result.error;
}
} catch (error) {
if (Joi.ValidationError.isError(error)) {
console.log('Validation failed:', error.annotate());
console.log('Original value:', error._original);
console.log('Error details:', error.details);
} else {
console.log('Other error:', error.message);
}
}Helper functions for working with validation errors.
interface ErrorUtilities {
/**
* Formats error details for display
* @param error - ValidationError instance
* @returns Formatted error information
*/
formatError(error: ValidationError): FormattedError;
/**
* Extracts error paths from ValidationError
* @param error - ValidationError instance
* @returns Array of error paths
*/
getErrorPaths(error: ValidationError): string[];
/**
* Groups errors by path
* @param error - ValidationError instance
* @returns Map of paths to error details
*/
groupErrorsByPath(error: ValidationError): Map<string, ValidationErrorItem[]>;
}
interface FormattedError {
message: string;
errors: {
path: string;
message: string;
type: string;
value?: any;
}[];
}Usage Examples:
// Custom error handling utilities
function formatValidationError(error) {
if (!Joi.ValidationError.isError(error)) {
return { message: error.message, errors: [] };
}
return {
message: error.message,
errors: error.details.map(detail => ({
path: detail.path.join('.'),
message: detail.message,
type: detail.type,
value: detail.context?.value
}))
};
}
function getErrorPaths(error) {
if (!Joi.ValidationError.isError(error)) {
return [];
}
return error.details.map(detail => detail.path.join('.'));
}
function groupErrorsByPath(error) {
const groups = new Map();
if (Joi.ValidationError.isError(error)) {
error.details.forEach(detail => {
const path = detail.path.join('.');
if (!groups.has(path)) {
groups.set(path, []);
}
groups.get(path).push(detail);
});
}
return groups;
}
// Usage in error handling
const schema = Joi.object({
name: Joi.string().min(3).required(),
email: Joi.string().email().required(),
age: Joi.number().min(18)
});
const { error } = schema.validate({
name: 'Jo',
email: 'invalid-email',
age: 16
});
if (error) {
console.log('Formatted error:', formatValidationError(error));
console.log('Error paths:', getErrorPaths(error));
console.log('Grouped errors:', groupErrorsByPath(error));
}Functions for extracting schema information and metadata.
interface SchemaIntrospection {
/**
* Gets schema description with full metadata
* @param schema - Schema to describe
* @returns Complete schema description
*/
describe(schema: Schema): SchemaDescription;
/**
* Extracts schema type information
* @param schema - Schema to analyze
* @returns Schema type details
*/
getSchemaType(schema: Schema): SchemaTypeInfo;
/**
* Gets all validation rules for schema
* @param schema - Schema to analyze
* @returns Array of validation rules
*/
getSchemaRules(schema: Schema): RuleInfo[];
}
interface SchemaDescription {
type: string;
flags?: Record<string, any>;
rules?: RuleDescription[];
preferences?: ValidationOptions;
allow?: any[];
invalid?: any[];
labels?: Record<string, string>;
metas?: any[];
notes?: string[];
tags?: string[];
examples?: ExampleDescription[];
}
interface SchemaTypeInfo {
type: string;
isRequired: boolean;
isOptional: boolean;
isForbidden: boolean;
hasDefault: boolean;
allowedValues?: any[];
invalidValues?: any[];
}Usage Examples:
// Schema introspection utilities
function analyzeSchema(schema) {
const description = schema.describe();
return {
type: description.type,
isRequired: description.flags?.presence === 'required',
isOptional: description.flags?.presence === 'optional',
isForbidden: description.flags?.presence === 'forbidden',
hasRules: Array.isArray(description.rules) && description.rules.length > 0,
allowedValues: description.allow,
invalidValues: description.invalid,
hasExamples: Array.isArray(description.examples) && description.examples.length > 0
};
}
// Usage
const complexSchema = Joi.object({
username: Joi.string().min(3).max(20).required(),
email: Joi.string().email().optional(),
role: Joi.string().valid('user', 'admin').default('user')
});
const analysis = analyzeSchema(complexSchema);
console.log('Schema analysis:', analysis);
// Extract specific schema information
const usernameSchema = complexSchema.extract(['username']);
const usernameAnalysis = analyzeSchema(usernameSchema);
console.log('Username field analysis:', usernameAnalysis);