Fast implementation of JSON-Patch (RFC-6902) with duplex capabilities for applying, generating, and observing JSON document changes
npx @tessl/cli install tessl/npm-fast-json-patch@3.1.0Fast JSON Patch is a high-performance TypeScript library that implements the JSON Patch standard (RFC-6902) for describing changes between JSON documents. It provides both core functionality for applying patches and duplex capabilities for observing objects and automatically generating patches when changes occur.
npm install fast-json-patchimport {
applyPatch,
applyOperation,
applyReducer,
compare,
observe,
unobserve,
generate,
validate,
validator,
getValueByPointer,
escapePathComponent,
unescapePathComponent,
deepClone,
JsonPatchError
} from "fast-json-patch";For CommonJS:
const {
applyPatch,
applyOperation,
compare,
observe,
validate,
JsonPatchError
} = require("fast-json-patch");Import types:
import type {
Operation,
Observer,
PatchResult,
OperationResult,
Validator,
JsonPatchErrorName,
AddOperation,
RemoveOperation,
ReplaceOperation,
MoveOperation,
CopyOperation,
TestOperation,
GetOperation
} from "fast-json-patch";Default import (for backwards compatibility):
import jsonpatch from "fast-json-patch";
// All functions available on the default export
const result = jsonpatch.applyPatch(document, patch);import { applyPatch, compare, observe } from "fast-json-patch";
// Apply a patch to a document
const document = { name: "John", age: 30 };
const patch = [
{ op: "replace", path: "/name", value: "Jane" },
{ op: "add", path: "/email", value: "jane@example.com" }
];
const result = applyPatch(document, patch);
console.log(result.newDocument); // { name: "Jane", age: 30, email: "jane@example.com" }
// Generate a patch by comparing two documents
const oldDoc = { name: "John", age: 30 };
const newDoc = { name: "Jane", age: 30, email: "jane@example.com" };
const generatedPatch = compare(oldDoc, newDoc);
console.log(generatedPatch); // [{ op: "replace", path: "/name", value: "Jane" }, ...]
// Observe changes and generate patches automatically
const obj = { counter: 0 };
const observer = observe(obj, (patches) => {
console.log("Changes detected:", patches);
});
obj.counter++; // Triggers patch generation
observer.unobserve(); // Stop observingFast JSON Patch is organized around three main modules:
The library supports multiple module formats (CommonJS/ES modules), provides comprehensive TypeScript definitions, and includes security protections against prototype pollution.
Core functionality for applying JSON patch operations to documents, with validation and error handling.
function applyPatch<T>(
document: T,
patch: ReadonlyArray<Operation>,
validateOperation?: boolean | Validator<T>,
mutateDocument?: boolean,
banPrototypeModifications?: boolean
): PatchResult<T>;
function applyOperation<T>(
document: T,
operation: Operation,
validateOperation?: boolean | Validator<T>,
mutateDocument?: boolean,
banPrototypeModifications?: boolean,
index?: number
): OperationResult<T>;Duplex functionality for observing objects and generating patches when changes are detected.
function observe<T>(
obj: Object | Array<T>,
callback?: (patches: Operation[]) => void
): Observer<T>;
function generate<T>(
observer: Observer<Object>,
invertible?: boolean
): Operation[];
function compare(
tree1: Object | any[],
tree2: Object | any[],
invertible?: boolean
): Operation[];Validation utilities for ensuring patch operations and sequences are correctly formatted and valid.
function validate<T>(
sequence: ReadonlyArray<Operation>,
document?: T,
externalValidator?: Validator<T>
): JsonPatchError | null;
function validator(
operation: Operation,
index: number,
document?: any,
existingPathFragment?: string
): void;Helper functions for working with JSON pointers and document traversal.
function getValueByPointer(document: any, pointer: string): any;
function escapePathComponent(path: string): string;
function unescapePathComponent(path: string): string;
function deepClone(obj: any): any;type Operation =
| AddOperation<any>
| RemoveOperation
| ReplaceOperation<any>
| MoveOperation
| CopyOperation
| TestOperation<any>
| GetOperation<any>;
interface AddOperation<T> {
op: 'add';
path: string;
value: T;
}
interface RemoveOperation {
op: 'remove';
path: string;
}
interface ReplaceOperation<T> {
op: 'replace';
path: string;
value: T;
}
interface MoveOperation {
op: 'move';
path: string;
from: string;
}
interface CopyOperation {
op: 'copy';
path: string;
from: string;
}
interface TestOperation<T> {
op: 'test';
path: string;
value: T;
}
interface GetOperation<T> {
op: '_get';
path: string;
value: T;
}interface OperationResult<T> {
removed?: any;
test?: boolean;
newDocument: T;
}
interface PatchResult<T> extends Array<OperationResult<T>> {
newDocument: T;
}
interface Observer<T> {
object: T;
patches: Operation[];
unobserve: () => void;
callback: (patches: Operation[]) => void;
}class JsonPatchError extends Error {
constructor(
message: string,
name: JsonPatchErrorName,
index?: number,
operation?: any,
tree?: any
);
name: JsonPatchErrorName;
index?: number;
operation?: any;
tree?: any;
}
type JsonPatchErrorName =
| 'SEQUENCE_NOT_AN_ARRAY'
| 'OPERATION_NOT_AN_OBJECT'
| 'OPERATION_OP_INVALID'
| 'OPERATION_PATH_INVALID'
| 'OPERATION_FROM_REQUIRED'
| 'OPERATION_VALUE_REQUIRED'
| 'OPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED'
| 'OPERATION_PATH_CANNOT_ADD'
| 'OPERATION_PATH_UNRESOLVABLE'
| 'OPERATION_FROM_UNRESOLVABLE'
| 'OPERATION_PATH_ILLEGAL_ARRAY_INDEX'
| 'OPERATION_VALUE_OUT_OF_BOUNDS'
| 'TEST_OPERATION_FAILED';interface Validator<T> {
(
operation: Operation,
index: number,
document: T,
existingPathFragment: string
): void;
}