Enhanced validation for JSON Schema Draft 2019-09 with dynamic references, unevaluated properties/items, and next generation features for advanced schema composition and validation.
Creates an Ajv validator instance configured for JSON Schema Draft 2019-09 with enhanced features automatically enabled.
/**
* Creates Ajv validator for JSON Schema Draft 2019-09
* @param options - Configuration options (dynamicRef, next, unevaluated enabled by default)
*/
constructor(options?: Options);
class Ajv2019 extends AjvCore {
constructor(opts: Options = {}) {
super({
...opts,
dynamicRef: true, // Automatically enabled
next: true, // Automatically enabled
unevaluated: true, // Automatically enabled
});
}
}Usage Examples:
import Ajv2019 from "ajv/dist/2019";
// Basic 2019-09 validator with enhanced features
const ajv = new Ajv2019();
// Custom options while maintaining 2019-09 features
const ajvCustom = new Ajv2019({
allErrors: true,
verbose: true,
strict: false
});Support for $dynamicRef and $dynamicAnchor enabling runtime schema resolution based on the validation context.
// Dynamic reference syntax in schemas
interface DynamicRefSchema {
$dynamicRef: string; // Reference to dynamic anchor
$dynamicAnchor?: string; // Dynamic anchor definition
[key: string]: any;
}Usage Examples:
import Ajv2019 from "ajv/dist/2019";
const ajv = new Ajv2019();
// Base schema with dynamic anchor
const baseSchema = {
$id: "https://example.com/base",
$dynamicAnchor: "meta",
type: "object",
properties: {
foo: { type: "string" }
}
};
// Extended schema that overrides the dynamic anchor
const extendedSchema = {
$id: "https://example.com/extended",
$dynamicAnchor: "meta",
allOf: [
{ $ref: "https://example.com/base" }
],
properties: {
foo: { type: "string" },
bar: { type: "number" }
}
};
// Schema using dynamic reference
const userSchema = {
$id: "https://example.com/user",
type: "object",
properties: {
profile: { $dynamicRef: "#meta" }
}
};
ajv.addSchema([baseSchema, extendedSchema, userSchema]);
// Dynamic resolution based on context
const validate = ajv.compile({
allOf: [
{ $ref: "https://example.com/extended" },
{ $ref: "https://example.com/user" }
]
});Advanced handling of unevaluatedProperties and unevaluatedItems for comprehensive schema validation.
// Unevaluated keywords in schemas
interface UnevaluatedSchema {
unevaluatedProperties?: boolean | AnySchema;
unevaluatedItems?: boolean | AnySchema;
[key: string]: any;
}Usage Examples:
import Ajv2019 from "ajv/dist/2019";
const ajv = new Ajv2019();
// Schema with unevaluated properties control
const schema = {
type: "object",
properties: {
name: { type: "string" }
},
if: {
properties: { type: { const: "user" } }
},
then: {
properties: {
email: { type: "string", format: "email" }
}
},
else: {
properties: {
code: { type: "string" }
}
},
unevaluatedProperties: false // Disallow any other properties
};
const validate = ajv.compile(schema);
// Valid: only evaluated properties
console.log(validate({
name: "Alice",
type: "user",
email: "alice@example.com"
})); // true
// Invalid: unevaluated property
console.log(validate({
name: "Alice",
type: "user",
email: "alice@example.com",
extra: "not allowed" // This will fail
})); // false
// Array example with unevaluated items
const arraySchema = {
type: "array",
prefixItems: [
{ type: "string" },
{ type: "number" }
],
if: {
minItems: 3
},
then: {
items: { type: "boolean" } // Additional items must be boolean
},
unevaluatedItems: false // No other items allowed
};Enhanced support for complex schema composition with proper evaluation tracking.
// Advanced composition schemas
interface CompositionSchema {
if?: AnySchema;
then?: AnySchema;
else?: AnySchema;
dependentSchemas?: { [property: string]: AnySchema };
$defs?: { [key: string]: AnySchema };
[key: string]: any;
}Usage Examples:
import Ajv2019 from "ajv/dist/2019";
const ajv = new Ajv2019();
// Complex conditional schema
const productSchema = {
$id: "https://example.com/product-2019",
type: "object",
properties: {
type: { enum: ["physical", "digital", "service"] },
name: { type: "string" },
price: { type: "number", minimum: 0 }
},
required: ["type", "name", "price"],
// Conditional requirements based on product type
if: {
properties: { type: { const: "physical" } }
},
then: {
properties: {
weight: { type: "number", minimum: 0 },
dimensions: {
type: "object",
properties: {
length: { type: "number" },
width: { type: "number" },
height: { type: "number" }
},
required: ["length", "width", "height"]
}
},
required: ["weight", "dimensions"]
},
else: {
if: {
properties: { type: { const: "digital" } }
},
then: {
properties: {
downloadUrl: { type: "string", format: "uri" },
fileSize: { type: "integer", minimum: 1 }
},
required: ["downloadUrl", "fileSize"]
},
else: {
// Service type
properties: {
duration: { type: "string" },
location: { type: "string" }
},
required: ["duration"]
}
},
unevaluated: false // No additional properties beyond evaluated ones
};
const validate = ajv.compile(productSchema);
// Physical product
console.log(validate({
type: "physical",
name: "Laptop",
price: 999.99,
weight: 2.5,
dimensions: { length: 30, width: 20, height: 2 }
})); // true
// Digital product
console.log(validate({
type: "digital",
name: "Software",
price: 49.99,
downloadUrl: "https://example.com/download",
fileSize: 1024000
})); // trueImproved reference resolution with support for anchors and recursive schemas.
// Enhanced reference patterns
interface EnhancedRefSchema {
$anchor?: string; // Named anchor for reference
$recursiveRef?: string; // Recursive reference (deprecated in favor of $dynamicRef)
$recursiveAnchor?: boolean; // Recursive anchor (deprecated)
[key: string]: any;
}Usage Examples:
import Ajv2019 from "ajv/dist/2019";
const ajv = new Ajv2019();
// Recursive schema using anchors
const treeSchema = {
$id: "https://example.com/tree",
$anchor: "node",
type: "object",
properties: {
value: { type: "string" },
children: {
type: "array",
items: { $ref: "#node" } // Recursive reference
}
},
required: ["value"]
};
ajv.addSchema(treeSchema);
const validate = ajv.getSchema("https://example.com/tree");
// Validate recursive tree structure
const treeData = {
value: "root",
children: [
{
value: "child1",
children: [
{ value: "grandchild1" },
{ value: "grandchild2" }
]
},
{ value: "child2" }
]
};
console.log(validate(treeData)); // trueKey differences when migrating from Draft 7 to 2019-09:
unevaluatedProperties, unevaluatedItems, dependentSchemas, dependentRequired$recursiveRef with $dynamicRefif/then/else evaluation trackingMigration Example:
// Draft 7 approach
const draft7Schema = {
type: "object",
properties: {
name: { type: "string" }
},
dependencies: {
creditCard: ["billingAddress"] // Dependencies as array
}
};
// 2019-09 approach
const draft2019Schema = {
type: "object",
properties: {
name: { type: "string" }
},
dependentRequired: {
creditCard: ["billingAddress"] // More explicit dependent requirements
},
dependentSchemas: {
creditCard: {
properties: {
billingAddress: {
type: "object",
properties: {
street: { type: "string" },
city: { type: "string" }
}
}
}
}
}
};