or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

core-validation.mderror-handling.mdindex.mdjtd-schemas.mdkeywords-vocabularies.mdschema-2019.mdschema-2020.mdschema-management.mdstandalone-generation.mdtypescript-integration.md
tile.json

schema-2020.mddocs/

JSON Schema 2020-12 Support

Latest JSON Schema Draft 2020-12 validation with all modern features, improvements, and the most current specification compliance for cutting-edge schema validation.

Capabilities

Ajv2020 Constructor

Creates an Ajv validator instance configured for JSON Schema Draft 2020-12 with all latest features automatically enabled.

/**
 * Creates Ajv validator for JSON Schema Draft 2020-12
 * @param options - Configuration options (dynamicRef, next, unevaluated enabled by default)
 */
constructor(options?: Options);

class Ajv2020 extends AjvCore {
  constructor(opts: Options = {}) {
    super({
      ...opts,
      dynamicRef: true,  // Automatically enabled
      next: true,        // Automatically enabled 
      unevaluated: true, // Automatically enabled
    });
  }
}

Usage Examples:

import Ajv2020 from "ajv/dist/2020";

// Basic 2020-12 validator with latest features
const ajv = new Ajv2020();

// Custom options while maintaining 2020-12 features
const ajvCustom = new Ajv2020({
  allErrors: true,
  verbose: true,
  strict: false,
  discriminator: true
});

Vocabulary-Based Validation

Enhanced vocabulary system allowing fine-grained control over which JSON Schema features are enabled.

// Vocabulary control in schemas
interface VocabularySchema {
  $vocabulary?: {
    [vocabularyId: string]: boolean;
  };
  [key: string]: any;
}

Usage Examples:

import Ajv2020 from "ajv/dist/2020";

const ajv = new Ajv2020();

// Schema with explicit vocabulary requirements
const schema = {
  $schema: "https://json-schema.org/draft/2020-12/schema",
  $vocabulary: {
    "https://json-schema.org/draft/2020-12/vocab/core": true,
    "https://json-schema.org/draft/2020-12/vocab/applicator": true,
    "https://json-schema.org/draft/2020-12/vocab/validation": true,
    "https://json-schema.org/draft/2020-12/vocab/format-annotation": false
  },
  type: "object",
  properties: {
    name: { type: "string" },
    email: { 
      type: "string",
      // format keyword ignored due to vocabulary setting
      format: "email"  
    }
  }
};

Prefix Items and Items

Modern array validation with prefixItems for tuple validation and enhanced items behavior.

// Modern array validation syntax
interface ArraySchema2020 {
  prefixItems?: AnySchema[];     // Schemas for specific positions
  items?: AnySchema;             // Schema for additional items
  unevaluatedItems?: AnySchema | boolean;
  minItems?: number;
  maxItems?: number;
  uniqueItems?: boolean;
  contains?: AnySchema;
  minContains?: number;
  maxContains?: number;
}

Usage Examples:

import Ajv2020 from "ajv/dist/2020";

const ajv = new Ajv2020();

// Tuple validation with prefixItems
const coordinateSchema = {
  type: "array",
  prefixItems: [
    { type: "number", description: "x coordinate" },
    { type: "number", description: "y coordinate" },
    { type: "number", description: "z coordinate", default: 0 }
  ],
  minItems: 2,
  maxItems: 3,
  unevaluatedItems: false  // No additional items allowed
};

const validateCoordinate = ajv.compile(coordinateSchema);

console.log(validateCoordinate([10, 20]));      // true - 2D coordinate
console.log(validateCoordinate([10, 20, 30]));  // true - 3D coordinate  
console.log(validateCoordinate([10, 20, 30, 40])); // false - too many items

// Mixed array validation
const mixedArraySchema = {
  type: "array",
  prefixItems: [
    { type: "string", description: "header" },
    { type: "number", description: "version" }
  ],
  items: {
    type: "object",
    properties: {
      id: { type: "string" },
      value: { type: "number" }
    },
    required: ["id", "value"]
  },
  minItems: 2
};

// Valid: header, version, then objects
const validMixed = ["Header", 1.0, { id: "a", value: 10 }, { id: "b", value: 20 }];
console.log(ajv.validate(mixedArraySchema, validMixed)); // true

Dynamic Anchor Improvements

Enhanced dynamic anchor system with clearer semantics and better resolution.

// Dynamic anchor patterns in 2020-12
interface DynamicAnchor2020 {
  $dynamicAnchor?: string;   // Improved dynamic anchor definition
  $dynamicRef?: string;      // Enhanced dynamic reference resolution
  [key: string]: any;
}

Usage Examples:

import Ajv2020 from "ajv/dist/2020";

const ajv = new Ajv2020();

// Meta-schema pattern with dynamic anchors
const baseMetaSchema = {
  $id: "https://example.com/meta/base",
  $dynamicAnchor: "meta",
  type: "object",
  properties: {
    type: { type: "string" },
    title: { type: "string" },
    description: { type: "string" }
  }
};

// Extended meta-schema
const extendedMetaSchema = {
  $id: "https://example.com/meta/extended",
  $dynamicAnchor: "meta",
  allOf: [{ $ref: "https://example.com/meta/base" }],
  properties: {
    type: { type: "string" },
    title: { type: "string" },
    description: { type: "string" },
    examples: {
      type: "array",
      items: true
    },
    deprecated: { type: "boolean" }
  }
};

// Schema that uses dynamic resolution
const schemaUsingMeta = {
  $id: "https://example.com/schema-with-meta",
  type: "object", 
  properties: {
    schema: { $dynamicRef: "#meta" }
  }
};

ajv.addSchema([baseMetaSchema, extendedMetaSchema, schemaUsingMeta]);

// Resolution depends on which meta-schema is in scope
const validate = ajv.compile({
  allOf: [
    { $ref: "https://example.com/meta/extended" },
    { $ref: "https://example.com/schema-with-meta" }
  ]
});

Content Schema Validation

Enhanced content validation for strings with specific media types and encodings.

// Content validation keywords
interface ContentSchema {
  contentMediaType?: string;    // MIME type of content
  contentEncoding?: string;     // Encoding of content (base64, etc.)
  contentSchema?: AnySchema;    // Schema for decoded content
  [key: string]: any;
}

Usage Examples:

import Ajv2020 from "ajv/dist/2020";

const ajv = new Ajv2020();

// JSON content validation
const configSchema = {
  type: "object",
  properties: {
    config: {
      type: "string",
      contentMediaType: "application/json",
      contentSchema: {
        type: "object",
        properties: {
          apiKey: { type: "string" },
          timeout: { type: "number", minimum: 0 }
        },
        required: ["apiKey"]
      }
    },
    certificate: {
      type: "string", 
      contentEncoding: "base64",
      contentMediaType: "application/x-pem-file"
    }
  }
};

const validate = ajv.compile(configSchema);

// Valid JSON content
console.log(validate({
  config: '{"apiKey": "abc123", "timeout": 5000}',
  certificate: "LS0tLS1CRUdJTi0..." // base64 encoded certificate
})); // true

// Invalid JSON content
console.log(validate({
  config: '{"timeout": 5000}', // missing required apiKey
  certificate: "LS0tLS1CRUdJTi0..."
})); // false

Annotation Collection

Comprehensive annotation collection system for gathering metadata during validation.

// Annotation collection in validation results
interface AnnotationCollection {
  annotations?: {
    [instancePath: string]: {
      [keyword: string]: any;
    };
  };
}

Usage Examples:

import Ajv2020 from "ajv/dist/2020";

const ajv = new Ajv2020({ 
  verbose: true,  // Enable annotation collection
  allErrors: true 
});

// Schema with annotations
const productSchema = {
  type: "object",
  title: "Product",
  description: "A product in our catalog",
  properties: {
    name: { 
      type: "string",
      title: "Product Name",
      examples: ["Widget", "Gadget"]
    },
    price: {
      type: "number",
      title: "Price in USD", 
      minimum: 0,
      examples: [9.99, 29.99, 199.99]
    },
    category: {
      type: "string",
      title: "Product Category",
      enum: ["electronics", "clothing", "books"],
      default: "electronics"
    }
  },
  required: ["name", "price"],
  examples: [
    { name: "Smartphone", price: 599.99, category: "electronics" },
    { name: "T-Shirt", price: 19.99, category: "clothing" }
  ]
};

const validate = ajv.compile(productSchema);

const product = { name: "Laptop", price: 999.99 };
const valid = validate(product);

// Access collected annotations
if (validate.evaluated) {
  console.log("Annotations:", validate.evaluated.annotations);
  console.log("Dynamic defaults:", validate.evaluated.dynamicDefaults);
}

Error Reporting Enhancements

Improved error reporting with better path resolution and more detailed error context.

// Enhanced error objects in 2020-12
interface ErrorObject2020 extends ErrorObject {
  instancePath: string;      // JSONPointer to the data
  schemaPath: string;        // JSONPointer to the schema
  unevaluated?: boolean;     // Whether error relates to unevaluated data
  dynamicAnchor?: string;    // Dynamic anchor context if applicable
}

Usage Examples:

import Ajv2020 from "ajv/dist/2020";

const ajv = new Ajv2020({ allErrors: true, verbose: true });

const complexSchema = {
  type: "object",
  properties: {
    user: {
      type: "object", 
      properties: {
        profile: {
          type: "object",
          properties: {
            name: { type: "string", minLength: 1 },
            email: { type: "string", format: "email" }
          },
          required: ["name", "email"],
          unevaluatedProperties: false
        }
      }
    }
  }
};

const invalidData = {
  user: {
    profile: {
      name: "",  // too short
      email: "invalid-email",  // invalid format
      extra: "not allowed"  // unevaluated property
    }
  }
};

const valid = ajv.validate(complexSchema, invalidData);

if (!valid && ajv.errors) {
  ajv.errors.forEach(error => {
    console.log(`Error at ${error.instancePath}: ${error.message}`);
    console.log(`Schema location: ${error.schemaPath}`);
    console.log(`Keyword: ${error.keyword}`);
    if (error.params) {
      console.log(`Parameters:`, error.params);
    }
  });
}

Migration from 2019-09

Key improvements in 2020-12 over 2019-09:

  1. Vocabulary System: More explicit vocabulary control
  2. Array Handling: prefixItems replaces array-form items
  3. Content Validation: Better support for contentSchema
  4. Annotation System: Improved annotation collection
  5. Dynamic Anchors: Clearer semantics and resolution

Migration Example:

// 2019-09 array validation
const schema2019 = {
  type: "array",
  items: [
    { type: "string" },    // First item
    { type: "number" }     // Second item  
  ],
  additionalItems: false   // No more items
};

// 2020-12 equivalent
const schema2020 = {
  type: "array",
  prefixItems: [
    { type: "string" },    // First item
    { type: "number" }     // Second item
  ],
  unevaluatedItems: false  // No more items
};