or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

change-observation.mdcore-operations.mdindex.mdjson-pointer-utilities.mdvalidation.md
tile.json

validation.mddocs/

Validation

Comprehensive validation utilities for ensuring JSON Patch operations and sequences are correctly formatted and can be safely applied to target documents.

Capabilities

Validate Operation Sequence

Validates an array of JSON Patch operations, optionally against a target document.

/**
 * Validates a sequence of operations. If document parameter is provided, 
 * the sequence is additionally validated against the object document.
 * @param sequence Array of operations to validate
 * @param document Optional document to validate operations against
 * @param externalValidator Optional custom validator function
 * @returns JsonPatchError if validation fails, undefined if valid
 */
function validate<T>(
  sequence: ReadonlyArray<Operation>,
  document?: T,
  externalValidator?: Validator<T>
): JsonPatchError | undefined;

Usage Examples:

import { validate } from "fast-json-patch";

// Basic structure validation
const patch = [
  { op: "add", path: "/name", value: "Alice" },
  { op: "remove", path: "/age" }
];

const error = validate(patch);
if (error) {
  console.error("Invalid patch:", error.message);
} else {
  console.log("Patch is valid");
}

// Validate against target document
const document = { name: "John", age: 30 };
const patchWithError = [
  { op: "remove", path: "/nonexistent" } // This path doesn't exist
];

const docError = validate(patchWithError, document);
if (docError) {
  console.error("Cannot apply patch:", docError.name); // "OPERATION_PATH_UNRESOLVABLE"
}

// Using custom validator
const customValidator = (op, index, doc, path) => {
  if (op.op === "add" && typeof op.value === "string" && op.value.length > 100) {
    throw new Error("String values cannot exceed 100 characters");
  }
};

const longStringPatch = [
  { op: "add", path: "/description", value: "a".repeat(150) }
];

const customError = validate(longStringPatch, document, customValidator);

Validate Single Operation

Validates a single JSON Patch operation, with detailed error reporting.

/**
 * Validates a single operation. Called from validate. Throws JsonPatchError in case of an error.
 * @param operation Operation object to validate
 * @param index Index of operation in the sequence
 * @param document Optional object where the operation is supposed to be applied
 * @param existingPathFragment Optional existing path fragment for context
 */
function validator(
  operation: Operation,
  index: number,
  document?: any,
  existingPathFragment?: string
): void;

Usage Examples:

import { validator } from "fast-json-patch";

try {
  // Validate operation structure
  validator({ op: "add", path: "/name", value: "Alice" }, 0);
  console.log("Operation is valid");
  
  // This will throw an error
  validator({ op: "invalid", path: "/name" }, 0);
} catch (error) {
  console.error("Validation failed:", error.message);
  console.error("Error code:", error.name); // "OPERATION_OP_INVALID"
}

// Validate against document context
const doc = { users: ["Alice"] };
try {
  validator(
    { op: "add", path: "/users/5", value: "Bob" },
    0,
    doc,
    "/users"
  );
} catch (error) {
  console.error("Invalid array index:", error.name); // "OPERATION_VALUE_OUT_OF_BOUNDS"
}

Validator Interface

Custom validator function interface for extending validation logic:

interface Validator<T> {
  /**
   * Custom validation function
   * @param operation The operation being validated
   * @param index The operation's index in the sequence
   * @param document The target document
   * @param existingPathFragment The existing path fragment for context
   */
  (
    operation: Operation,
    index: number,
    document: T,
    existingPathFragment: string
  ): void;
}

Error Types

JsonPatchError Class

Comprehensive error class for JSON Patch validation failures:

class JsonPatchError extends Error {
  constructor(
    message: string,
    name: JsonPatchErrorName,
    index?: number,
    operation?: any,
    tree?: any
  );
  
  /** Descriptive error name */
  name: JsonPatchErrorName;
  /** Index of the failing operation */
  index?: number;
  /** The operation that caused the error */
  operation?: any;
  /** The document being operated on */
  tree?: any;
}

Error Names

All possible validation error types:

type JsonPatchErrorName = 
  | 'SEQUENCE_NOT_AN_ARRAY'              // Patch sequence must be an array
  | 'OPERATION_NOT_AN_OBJECT'            // Operation must be an object
  | 'OPERATION_OP_INVALID'               // Invalid operation type
  | 'OPERATION_PATH_INVALID'             // Invalid path format
  | 'OPERATION_FROM_REQUIRED'            // Missing 'from' property for move/copy
  | 'OPERATION_VALUE_REQUIRED'           // Missing 'value' property for add/replace/test
  | 'OPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED' // Value cannot contain undefined
  | 'OPERATION_PATH_CANNOT_ADD'          // Cannot add at the specified path
  | 'OPERATION_PATH_UNRESOLVABLE'        // Path does not exist in document
  | 'OPERATION_FROM_UNRESOLVABLE'        // From path does not exist in document
  | 'OPERATION_PATH_ILLEGAL_ARRAY_INDEX' // Invalid array index format
  | 'OPERATION_VALUE_OUT_OF_BOUNDS'      // Array index out of bounds
  | 'TEST_OPERATION_FAILED';             // Test operation comparison failed

Validation Rules

Operation Structure

  1. Operation Object: Must be a non-null object (not array)
  2. Operation Type: Must be one of: 'add', 'remove', 'replace', 'move', 'copy', 'test'
  3. Path Property: Must be a string starting with "/" (or empty string for root)

Operation-Specific Rules

Add Operations:

  • Must have value property
  • Value cannot contain undefined
  • Array indices must be valid integers or "-" for append
  • Cannot add beyond array bounds (index > length)

Remove Operations:

  • Path must exist in the target document
  • No additional properties required

Replace Operations:

  • Must have value property
  • Value cannot contain undefined
  • Path must exist in the target document

Move Operations:

  • Must have from property (string)
  • Both path and from must be valid paths
  • from path must exist in the target document

Copy Operations:

  • Must have from property (string)
  • from path must exist in the target document
  • Destination path validated same as add operations

Test Operations:

  • Must have value property
  • Path must exist in the target document
  • Throws TEST_OPERATION_FAILED if values don't match

Document Context Validation

When validating against a document:

  1. Path Resolution: Verifies all paths can be resolved in the document
  2. Type Consistency: Ensures operations are appropriate for target types
  3. Array Bounds: Validates array indices are within bounds
  4. Property Existence: Confirms required properties exist for remove/replace/test operations

Security Validations

  1. Prototype Pollution Protection: Prevents modification of __proto__ and constructor.prototype
  2. Path Traversal: Validates JSON pointer format compliance
  3. Undefined Values: Prevents undefined values in patches (not JSON serializable)

Custom Validation

Extend validation with custom logic:

import { validate, Validator } from "fast-json-patch";

const businessValidator: Validator<any> = (operation, index, document, path) => {
  // Business logic validation
  if (operation.op === "add" && operation.path.startsWith("/admin/")) {
    throw new Error("Admin modifications not allowed");
  }
  
  // Type-specific validation
  if (operation.op === "replace" && operation.path === "/email") {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(operation.value)) {
      throw new Error("Invalid email format");
    }
  }
};

// Use with validation
const error = validate(patch, document, businessValidator);

This validation system ensures patch operations are safe, correctly formatted, and can be successfully applied to target documents while providing detailed error information for debugging.