or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

core-operations.mddiffpatcher-class.mdformatters.mdindex.mdoptions-configuration.md
tile.json

tessl/npm-jsondiffpatch

JSON diff & patch library with support for objects, arrays, text diffs, and multiple output formats

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/jsondiffpatch@0.7.x

To install, run

npx @tessl/cli install tessl/npm-jsondiffpatch@0.7.0

index.mddocs/

jsondiffpatch

jsondiffpatch is a comprehensive JSON diff & patch library that detects differences between JavaScript objects and arrays, generates change deltas, and applies patches to transform objects from one state to another. It supports intelligent array diffing using LCS algorithm, multiple output formats, text diffing for strings, and extensive customization options.

Package Information

  • Package Name: jsondiffpatch
  • Package Type: npm
  • Language: TypeScript/JavaScript
  • Installation: npm install jsondiffpatch

Core Imports

import { create, diff, patch, unpatch, reverse, clone, DiffPatcher } from "jsondiffpatch";

For text diff support:

import { create, diff, patch, unpatch, reverse, clone, DiffPatcher } from "jsondiffpatch/with-text-diffs";

CommonJS:

const { create, diff, patch, unpatch, reverse, clone, DiffPatcher } = require("jsondiffpatch");

Basic Usage

import { diff, patch, reverse } from "jsondiffpatch";

// Generate diff between two objects
const left = { name: "Alice", age: 25, active: true };
const right = { name: "Alice", age: 26, active: false, role: "admin" };

const delta = diff(left, right);
console.log(delta);
// { age: [25, 26], active: [true, false], role: ["admin"] }

// Apply patch to get target object
const result = patch(left, delta);
console.log(result);
// { name: "Alice", age: 26, active: false, role: "admin" }

// Reverse a patch
const reverseDelta = reverse(delta);
const original = patch(result, reverseDelta);
console.log(original);
// { name: "Alice", age: 25, active: true }

Architecture

jsondiffpatch is built around several key components:

  • DiffPatcher Class: Main class providing diff, patch, reverse, and utility operations
  • Processing Pipeline: Filter-based architecture using pipes for extensible diff/patch operations
  • Context System: Specialized contexts (DiffContext, PatchContext, ReverseContext) for each operation type
  • Delta Types: Structured representation of changes (added, modified, deleted, moved, text diffs)
  • Formatters: Multiple output formats including console, HTML, JSON Patch, and annotated formats
  • Filter System: Modular filters for handling arrays, objects, text, dates, and trivial cases

Capabilities

Core Operations

Primary diff and patch operations for generating and applying changes between JavaScript values.

function diff(left: unknown, right: unknown): Delta;
function patch(left: unknown, delta: Delta): unknown;
function unpatch(right: unknown, delta: Delta): unknown;
function reverse(delta: Delta): Delta;
function clone(value: unknown): unknown;
function create(options?: Options): DiffPatcher;

Core Operations

DiffPatcher Class

Object-oriented interface providing full control over diff and patch operations with customizable options.

class DiffPatcher {
  constructor(options?: Options);
  diff(left: unknown, right: unknown): Delta;
  patch(left: unknown, delta: Delta): unknown;
  unpatch(right: unknown, delta: Delta): unknown;
  reverse(delta: Delta): Delta;
  clone(value: unknown): unknown;
  options(options?: Options): Options;
}

DiffPatcher Class

Formatters

Multiple output formats for visualizing and processing diffs including console output, HTML visualization, JSON Patch compatibility, and annotated formatting.

// Console formatter
import * as console from "jsondiffpatch/formatters/console";
function format(delta: Delta, left?: unknown): string;
function log(delta: Delta, left?: unknown): void;

// HTML formatter  
import * as html from "jsondiffpatch/formatters/html";
function format(delta: Delta, left?: unknown): string;
function showUnchanged(show?: boolean, node?: Element, delay?: number): void;
function hideUnchanged(node?: Element, delay?: number): void;

// JSON Patch formatter
import * as jsonpatch from "jsondiffpatch/formatters/jsonpatch";
function format(delta: Delta): Op[];
function patch(target: unknown, operations: Op[]): void;

// Annotated formatter
import * as annotated from "jsondiffpatch/formatters/annotated";
function format(delta: Delta, left?: unknown): string;

Formatters

Options and Configuration

Comprehensive configuration system for customizing diff behavior including array handling, text diffing, property filtering, and output formatting.

interface Options {
  objectHash?: (item: object, index?: number) => string | undefined;
  matchByPosition?: boolean;
  arrays?: {
    detectMove?: boolean;
    includeValueOnMove?: boolean;
  };
  textDiff?: {
    diffMatchPatch: typeof diff_match_patch;
    minLength?: number;
  };
  propertyFilter?: (name: string, context: DiffContext) => boolean;
  cloneDiffValues?: boolean | ((value: unknown) => unknown);
  omitRemovedValues?: boolean;
}

Options and Configuration

Delta Types

jsondiffpatch uses structured delta objects to represent different types of changes:

type Delta = AddedDelta | ModifiedDelta | DeletedDelta | ObjectDelta | ArrayDelta | MovedDelta | TextDiffDelta | undefined;

// Basic change types
type AddedDelta = [unknown];                    // [newValue]
type ModifiedDelta = [unknown, unknown];        // [oldValue, newValue]  
type DeletedDelta = [unknown, 0, 0];           // [oldValue, 0, 0]

// Complex change types
type MovedDelta = [unknown, number, 3];        // [value, newIndex, 3]
type TextDiffDelta = [string, 0, 2];           // [diffString, 0, 2]
interface ObjectDelta { [property: string]: Delta; }
interface ArrayDelta { _t: "a"; [index: number | `${number}`]: Delta; }

Type Guards

function isAddedDelta(delta: Delta): delta is AddedDelta;
function isModifiedDelta(delta: Delta): delta is ModifiedDelta;
function isDeletedDelta(delta: Delta): delta is DeletedDelta;
function isObjectDelta(delta: Delta): delta is ObjectDelta;
function isArrayDelta(delta: Delta): delta is ArrayDelta;
function isMovedDelta(delta: Delta): delta is MovedDelta;
function isTextDiffDelta(delta: Delta): delta is TextDiffDelta;

Context Types

Context objects provide state and configuration for diff, patch, and reverse operations. These are primarily used when creating custom filters or advanced pipeline customization.

// Base context class
abstract class Context<TResult> {
  abstract pipe: string;
  result?: TResult;
  hasResult?: boolean;
  exiting?: boolean;
  parent?: Context<TResult>;
  childName?: string | number;
  root?: Context<TResult>;
  options?: Options;
  children?: Context<TResult>[];
  nextAfterChildren?: Context<TResult> | null;
  next?: Context<TResult> | null;
  
  setResult(result: TResult): this;
  exit(): this;
  push(child: Context<TResult>, name?: string | number): this;
}

// Diff operation context
class DiffContext extends Context<Delta> {
  pipe: "diff";
  left: unknown;
  right: unknown;
  leftType?: string;
  rightType?: string;
  leftIsArray?: boolean;
  rightIsArray?: boolean;
  
  constructor(left: unknown, right: unknown);
  prepareDeltaResult<T extends Delta>(result: T): T;
  setResult(result: Delta): this;
}

// Patch operation context  
class PatchContext extends Context<unknown> {
  pipe: "patch";
  left: unknown;
  delta: Delta;
  
  constructor(left: unknown, delta: Delta);
}

// Reverse operation context
class ReverseContext extends Context<Delta> {
  pipe: "reverse";
  delta: Delta;
  
  constructor(delta: Delta);
}

Usage in Custom Filters:

import { DiffContext, PatchContext, ReverseContext } from "jsondiffpatch";

// Example custom filter
const customFilter = (context) => {
  if (context.pipe === "diff") {
    const diffCtx = context; // DiffContext
    console.log(`Diffing: ${typeof diffCtx.left} -> ${typeof diffCtx.right}`);
    
    // Access parent context for nested operations
    if (diffCtx.parent) {
      console.log(`Parent operation: ${diffCtx.parent.pipe}`);
    }
    
    // Set custom result
    if (diffCtx.left === diffCtx.right) {
      diffCtx.setResult(undefined); // No difference
      diffCtx.exit(); // Skip further processing
    }
  }
};

// Context hierarchy for nested objects
const result = diff({ user: { name: "Alice" } }, { user: { name: "Bob" } });
// Creates nested DiffContext instances:
// - Root context for entire object
// - Child context for 'user' property  
// - Child context for 'name' property

Utilities

/**
 * JSON.parse reviver function for converting ISO date strings back to Date objects
 * Handles ISO 8601 format: YYYY-MM-DDTHH:mm:ss.sssZ or YYYY-MM-DDTHH:mm:ss±HH:mm
 * @param key - Property key (unused)
 * @param value - Property value to potentially revive
 * @returns Date object if value matches ISO date pattern, otherwise original value
 */
function dateReviver(key: string, value: unknown): unknown;

/**
 * Create deep clone of any value using the default DiffPatcher instance
 * @param value - Value to clone
 * @returns Deep cloned copy
 */
function clone(value: unknown): unknown;

Date Reviver Usage:

import { dateReviver } from "jsondiffpatch";

// Parse JSON with automatic date revival
const jsonString = '{"created": "2023-12-25T10:30:00.000Z", "name": "example"}';
const parsed = JSON.parse(jsonString, dateReviver);

console.log(parsed.created instanceof Date); // true
console.log(parsed.created.getFullYear());   // 2023
console.log(parsed.name);                    // "example" (unchanged)

// Handles various ISO 8601 formats
const formats = [
  "2023-12-25T10:30:00Z",           // UTC
  "2023-12-25T10:30:00.123Z",       // UTC with milliseconds  
  "2023-12-25T10:30:00+05:30",     // Timezone offset
  "2023-12-25T10:30:00-08:00"      // Negative timezone
];

formats.forEach(dateStr => {
  const result = dateReviver("", dateStr);
  console.log(result instanceof Date); // true for all
});

CLI Tool

jsondiffpatch includes a command-line interface for diffing JSON files with support for HTTP URLs and multiple output formats:

jsondiffpatch left.json right.json [options]

Options:

  • --format=console|json|json-compact|jsonpatch - Output format (default: console)
  • --omit-removed-values - Exclude removed values from output (makes diffs irreversible)
  • --no-moves - Disable array move detection (improves performance on large arrays)
  • --no-text-diff - Disable text diffing for long strings
  • --object-keys=prop1,prop2 - Object matching keys for arrays (default: id,key)
  • --help - Show usage information with example output

Exit Codes:

  • 0 - No differences found between files
  • 1 - Differences found (standard for diff tools)
  • 2 - Error occurred (invalid arguments, file not found, etc.)

Input Sources:

  • Local JSON files: file1.json file2.json
  • HTTP/HTTPS URLs: Automatically fetches and parses JSON from URLs
  • Mixed sources: local.json https://api.example.com/data

Usage Examples:

# Basic diff with colorized console output
jsondiffpatch file1.json file2.json

# Raw JSON delta output
jsondiffpatch file1.json file2.json --format=json

# Compact JSON (single line)
jsondiffpatch file1.json file2.json --format=json-compact

# RFC 6902 JSON Patch format
jsondiffpatch file1.json file2.json --format=jsonpatch

# Disable move detection for performance
jsondiffpatch large1.json large2.json --no-moves

# Compare remote APIs
jsondiffpatch https://api.example.com/v1 https://api.example.com/v2

# Object matching by specific keys (for array elements)
jsondiffpatch users1.json users2.json --object-keys=id,email

# Omit old values (smaller output, cannot reverse)
jsondiffpatch old.json new.json --omit-removed-values

# Help with live demo
jsondiffpatch --help

Default Behavior:

  • Uses text diffing by default (via jsondiffpatch/with-text-diffs)
  • Array objects matched by id or key properties first, then by position
  • Move detection enabled for arrays
  • Console output with ANSI colors for terminal display