(oldValue: Schema.Json, newValue: Schema.Json): JsonPatchComputes a structural patch that transforms oldValue into newValue.
When to use
Use to compute a JSON Patch from before and after JSON documents, detect structural changes, or create deterministic update operations.
Details
Generates a structural diff between two JSON values, producing a patch that
yields newValue when applied to oldValue. It returns an empty array when
values are identical, recursively diffs nested structures, emits root
replace operations for primitive changes, and processes object keys in
sorted order for stable output.
Gotchas
Arrays are compared by index position, with no move or copy detection. Array removals are emitted from highest to lowest index to prevent index shifting. The output is deterministic but not guaranteed to be minimal.
Example (Computing object diff)
import { JsonPatch } from "effect"
const oldValue = { users: [{ id: 1, name: "Alice" }], count: 1 }
const newValue = { users: [{ id: 1, name: "Bob" }, { id: 2, name: "Charlie" }], count: 2 }
const patch = JsonPatch.get(oldValue, newValue)
// [
// { op: "replace", path: "/users/0/name", value: "Bob" },
// { op: "add", path: "/users/1", value: { id: 2, name: "Charlie" } },
// { op: "replace", path: "/count", value: 2 }
// ]export function function get(
oldValue: Schema.Json,
newValue: Schema.Json
): JsonPatch
Computes a structural patch that transforms oldValue into newValue.
When to use
Use to compute a JSON Patch from before and after JSON documents, detect
structural changes, or create deterministic update operations.
Details
Generates a structural diff between two JSON values, producing a patch that
yields newValue when applied to oldValue. It returns an empty array when
values are identical, recursively diffs nested structures, emits root
replace operations for primitive changes, and processes object keys in
sorted order for stable output.
Gotchas
Arrays are compared by index position, with no move or copy detection. Array
removals are emitted from highest to lowest index to prevent index shifting.
The output is deterministic but not guaranteed to be minimal.
Example (Computing object diff)
import { JsonPatch } from "effect"
const oldValue = { users: [{ id: 1, name: "Alice" }], count: 1 }
const newValue = { users: [{ id: 1, name: "Bob" }, { id: 2, name: "Charlie" }], count: 2 }
const patch = JsonPatch.get(oldValue, newValue)
// [
// { op: "replace", path: "/users/0/name", value: "Bob" },
// { op: "add", path: "/users/1", value: { id: 2, name: "Charlie" } },
// { op: "replace", path: "/count", value: 2 }
// ]
get(oldValue: Schema.JsonoldValue: import SchemaSchema.type Json =
| string
| number
| boolean
| Schema.JsonArray
| Schema.JsonObject
| null
Recursive TypeScript type for any valid immutable JSON value: null,
number, boolean, string, a readonly array of Json values, or a
readonly record of string → Json. For the corresponding schema, see the
Json
const.
Schema that accepts and validates any immutable JSON-compatible value.
Example (Validating a JSON value)
import { Schema } from "effect"
const result = Schema.decodeUnknownOption(Schema.Json)({ key: [1, true, null] })
console.log(result._tag) // "Some"
Json, newValue: Schema.JsonnewValue: import SchemaSchema.type Json =
| string
| number
| boolean
| Schema.JsonArray
| Schema.JsonObject
| null
Recursive TypeScript type for any valid immutable JSON value: null,
number, boolean, string, a readonly array of Json values, or a
readonly record of string → Json. For the corresponding schema, see the
Json
const.
Schema that accepts and validates any immutable JSON-compatible value.
Example (Validating a JSON value)
import { Schema } from "effect"
const result = Schema.decodeUnknownOption(Schema.Json)({ key: [1, true, null] })
console.log(result._tag) // "Some"
Json): type JsonPatch =
readonly JsonPatchOperation[]
A JSON Patch document (an ordered list of operations).
When to use
Use to store, serialize, pass, or validate complete patch documents.
Details
Represents a complete transformation as a readonly sequence of immutable
operations. Operations are applied sequentially from first to last, and later
operations observe the document state produced by earlier operations. An empty
array represents a no-op patch and returns the original document.
Example (Defining a multi-operation patch)
import { JsonPatch } from "effect"
const patch: JsonPatch.JsonPatch = [
{ op: "add", path: "/items/-", value: "apple" },
{ op: "replace", path: "/count", value: 5 },
{ op: "remove", path: "/oldField" }
]
const result = JsonPatch.apply(patch, { count: 3, oldField: "value" })
// { count: 5, items: ["apple"] }
JsonPatch {
if (var Object: ObjectConstructorProvides functionality common to all JavaScript objects.
Object.ObjectConstructor.is(value1: any, value2: any): booleanReturns true if the values are the same value, false otherwise.
is(oldValue: Schema.JsonoldValue, newValue: Schema.JsonnewValue)) return []
const const patches: Array<JsonPatchOperation>patches: interface Array<T>Array<type JsonPatchOperation =
| {
readonly op: "add"
readonly path: string
readonly value: Schema.Json
readonly description?: string
}
| {
readonly op: "remove"
readonly path: string
readonly description?: string
}
| {
readonly op: "replace"
readonly path: string
readonly value: Schema.Json
readonly description?: string
}
A single JSON Patch operation.
When to use
Use to manually construct patch operations, accept patch operations from
callers, or type-check patch operation structures.
Details
Represents one transformation step in a JSON Patch document. This is a subset
of RFC 6902, restricted to operations that can be applied deterministically
without additional context. All fields are readonly, paths use JSON Pointer
syntax, and the empty string "" refers to the root document. Operations are
discriminated by the op field, and the optional description field can be
used for documentation.
Example (Defining all operation types)
import { JsonPatch } from "effect"
const addOp: JsonPatch.JsonPatchOperation = {
op: "add",
path: "/users/-",
value: { id: 1, name: "Alice" }
}
const removeOp: JsonPatch.JsonPatchOperation = {
op: "remove",
path: "/users/0"
}
const replaceOp: JsonPatch.JsonPatchOperation = {
op: "replace",
path: "/users/0/name",
value: "Bob"
}
JsonPatchOperation> = []
if (var Array: ArrayConstructorArray.ArrayConstructor.isArray(arg: any): arg is any[]isArray(oldValue: Schema.JsonoldValue) && var Array: ArrayConstructorArray.ArrayConstructor.isArray(arg: any): arg is any[]isArray(newValue: Schema.JsonnewValue)) {
const const len1: numberlen1 = oldValue: Schema.JsonoldValue.Array<any>.length: numberGets or sets the length of the array. This is a number one higher than the highest index in the array.
length
const const len2: numberlen2 = newValue: Schema.JsonnewValue.Array<any>.length: numberGets or sets the length of the array. This is a number one higher than the highest index in the array.
length
// Compare shared prefix by index
const const shared: numbershared = var Math: MathAn intrinsic object that provides basic mathematics functionality and constants.
Math.Math.min(...values: number[]): numberReturns the smaller of a set of supplied numeric expressions.
min(const len1: numberlen1, const len2: numberlen2)
for (let let i: numberi = 0; let i: numberi < const shared: numbershared; let i: numberi++) {
const const path: stringpath = `/${let i: numberi}`
const const patch: JsonPatchconst patch: {
length: number;
toString: () => string;
toLocaleString: { (): string; (locales: string | string[], options?: Intl.NumberFormatOptions & Intl.DateTimeFormatOptions): string };
concat: { (...items: Array<ConcatArray<JsonPatchOperation>>): Array<JsonPatchOperation>; (...items: Array<JsonPatchOperation | ConcatArray<JsonPatchOperation>>): Array<JsonPatchOperation> };
join: (separator?: string) => string;
slice: (start?: number, end?: number) => Array<JsonPatchOperation>;
indexOf: (searchElement: JsonPatchOperation, fromIndex?: number) => number;
lastIndexOf: (searchElement: JsonPatchOperation, fromIndex?: number) => number;
every: { (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => value is S, thisArg?: any): this is readonly S[]; (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOp…;
some: (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => unknown, thisArg?: any) => boolean;
forEach: (callbackfn: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => void, thisArg?: any) => void;
map: (callbackfn: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => U, thisArg?: any) => Array<U>;
filter: { (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => value is S, thisArg?: any): Array<S>; (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) =>…;
reduce: { (callbackfn: (previousValue: JsonPatchOperation, currentValue: JsonPatchOperation, currentIndex: number, array: ReadonlyArray<JsonPatchOperation>) => JsonPatchOperation): JsonPatchOperation; (callbackfn: (previousValue: JsonPatchOperatio…;
reduceRight: { (callbackfn: (previousValue: JsonPatchOperation, currentValue: JsonPatchOperation, currentIndex: number, array: ReadonlyArray<JsonPatchOperation>) => JsonPatchOperation): JsonPatchOperation; (callbackfn: (previousValue: JsonPatchOperatio…;
find: { (predicate: (value: JsonPatchOperation, index: number, obj: ReadonlyArray<JsonPatchOperation>) => value is S, thisArg?: any): S | undefined; (predicate: (value: JsonPatchOperation, index: number, obj: ReadonlyArray<JsonPatchOperation>) =…;
findIndex: (predicate: (value: JsonPatchOperation, index: number, obj: ReadonlyArray<JsonPatchOperation>) => unknown, thisArg?: any) => number;
entries: () => ArrayIterator<[number, JsonPatchOperation]>;
keys: () => ArrayIterator<number>;
values: () => ArrayIterator<JsonPatchOperation>;
includes: (searchElement: JsonPatchOperation, fromIndex?: number) => boolean;
flatMap: (callback: (this: This, value: JsonPatchOperation, index: number, array: Array<JsonPatchOperation>) => U | ReadonlyArray<U>, thisArg?: This | undefined) => Array<U>;
flat: (this: A, depth?: D | undefined) => Array<FlatArray<A, D>>;
at: (index: number) => JsonPatchOperation | undefined;
findLast: { (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => value is S, thisArg?: any): S | undefined; (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation…;
findLastIndex: (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => unknown, thisArg?: any) => number;
toReversed: () => Array<JsonPatchOperation>;
toSorted: (compareFn?: ((a: JsonPatchOperation, b: JsonPatchOperation) => number) | undefined) => Array<JsonPatchOperation>;
toSpliced: { (start: number, deleteCount: number, ...items: Array<JsonPatchOperation>): Array<JsonPatchOperation>; (start: number, deleteCount?: number): Array<JsonPatchOperation> };
with: (index: number, value: JsonPatchOperation) => Array<JsonPatchOperation>;
}
patch = function get(
oldValue: Schema.Json,
newValue: Schema.Json
): JsonPatch
Computes a structural patch that transforms oldValue into newValue.
When to use
Use to compute a JSON Patch from before and after JSON documents, detect
structural changes, or create deterministic update operations.
Details
Generates a structural diff between two JSON values, producing a patch that
yields newValue when applied to oldValue. It returns an empty array when
values are identical, recursively diffs nested structures, emits root
replace operations for primitive changes, and processes object keys in
sorted order for stable output.
Gotchas
Arrays are compared by index position, with no move or copy detection. Array
removals are emitted from highest to lowest index to prevent index shifting.
The output is deterministic but not guaranteed to be minimal.
Example (Computing object diff)
import { JsonPatch } from "effect"
const oldValue = { users: [{ id: 1, name: "Alice" }], count: 1 }
const newValue = { users: [{ id: 1, name: "Bob" }, { id: 2, name: "Charlie" }], count: 2 }
const patch = JsonPatch.get(oldValue, newValue)
// [
// { op: "replace", path: "/users/0/name", value: "Bob" },
// { op: "add", path: "/users/1", value: { id: 2, name: "Charlie" } },
// { op: "replace", path: "/count", value: 2 }
// ]
get(oldValue: Schema.JsonoldValue[let i: numberi], newValue: Schema.JsonnewValue[let i: numberi])
for (const const op: JsonPatchOperationop of const patch: JsonPatchconst patch: {
length: number;
toString: () => string;
toLocaleString: { (): string; (locales: string | string[], options?: Intl.NumberFormatOptions & Intl.DateTimeFormatOptions): string };
concat: { (...items: Array<ConcatArray<JsonPatchOperation>>): Array<JsonPatchOperation>; (...items: Array<JsonPatchOperation | ConcatArray<JsonPatchOperation>>): Array<JsonPatchOperation> };
join: (separator?: string) => string;
slice: (start?: number, end?: number) => Array<JsonPatchOperation>;
indexOf: (searchElement: JsonPatchOperation, fromIndex?: number) => number;
lastIndexOf: (searchElement: JsonPatchOperation, fromIndex?: number) => number;
every: { (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => value is S, thisArg?: any): this is readonly S[]; (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOp…;
some: (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => unknown, thisArg?: any) => boolean;
forEach: (callbackfn: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => void, thisArg?: any) => void;
map: (callbackfn: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => U, thisArg?: any) => Array<U>;
filter: { (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => value is S, thisArg?: any): Array<S>; (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) =>…;
reduce: { (callbackfn: (previousValue: JsonPatchOperation, currentValue: JsonPatchOperation, currentIndex: number, array: ReadonlyArray<JsonPatchOperation>) => JsonPatchOperation): JsonPatchOperation; (callbackfn: (previousValue: JsonPatchOperatio…;
reduceRight: { (callbackfn: (previousValue: JsonPatchOperation, currentValue: JsonPatchOperation, currentIndex: number, array: ReadonlyArray<JsonPatchOperation>) => JsonPatchOperation): JsonPatchOperation; (callbackfn: (previousValue: JsonPatchOperatio…;
find: { (predicate: (value: JsonPatchOperation, index: number, obj: ReadonlyArray<JsonPatchOperation>) => value is S, thisArg?: any): S | undefined; (predicate: (value: JsonPatchOperation, index: number, obj: ReadonlyArray<JsonPatchOperation>) =…;
findIndex: (predicate: (value: JsonPatchOperation, index: number, obj: ReadonlyArray<JsonPatchOperation>) => unknown, thisArg?: any) => number;
entries: () => ArrayIterator<[number, JsonPatchOperation]>;
keys: () => ArrayIterator<number>;
values: () => ArrayIterator<JsonPatchOperation>;
includes: (searchElement: JsonPatchOperation, fromIndex?: number) => boolean;
flatMap: (callback: (this: This, value: JsonPatchOperation, index: number, array: Array<JsonPatchOperation>) => U | ReadonlyArray<U>, thisArg?: This | undefined) => Array<U>;
flat: (this: A, depth?: D | undefined) => Array<FlatArray<A, D>>;
at: (index: number) => JsonPatchOperation | undefined;
findLast: { (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => value is S, thisArg?: any): S | undefined; (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation…;
findLastIndex: (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => unknown, thisArg?: any) => number;
toReversed: () => Array<JsonPatchOperation>;
toSorted: (compareFn?: ((a: JsonPatchOperation, b: JsonPatchOperation) => number) | undefined) => Array<JsonPatchOperation>;
toSpliced: { (start: number, deleteCount: number, ...items: Array<JsonPatchOperation>): Array<JsonPatchOperation>; (start: number, deleteCount?: number): Array<JsonPatchOperation> };
with: (index: number, value: JsonPatchOperation) => Array<JsonPatchOperation>;
}
patch) {
function prefixPathInPlace(
op: JsonPatchOperation,
parent: string
): void
prefixPathInPlace(const op: JsonPatchOperationop, const path: stringpath)
const patches: Array<JsonPatchOperation>patches.Array<JsonPatchOperation>.push(...items: JsonPatchOperation[]): numberAppends new elements to the end of an array, and returns the new length of the array.
push(const op: JsonPatchOperationop)
}
}
// Remove from end to start so later indices do not shift.
for (let let i: numberi = const len1: numberlen1 - 1; let i: numberi >= const len2: numberlen2; let i: numberi--) {
const patches: Array<JsonPatchOperation>patches.Array<JsonPatchOperation>.push(...items: JsonPatchOperation[]): numberAppends new elements to the end of an array, and returns the new length of the array.
push({ op: "remove"op: "remove", path: stringJSON Pointer to the target location.
When to use
Use to identify which location the remove operation deletes.
path: `/${let i: numberi}` })
}
// Add from beginning to end.
for (let let i: numberi = const len1: numberlen1; let i: numberi < const len2: numberlen2; let i: numberi++) {
const patches: Array<JsonPatchOperation>patches.Array<JsonPatchOperation>.push(...items: JsonPatchOperation[]): numberAppends new elements to the end of an array, and returns the new length of the array.
push({ op: "add"op: "add", path: stringJSON Pointer to the target location. For arrays, the last token may be -
to append.
When to use
Use to identify where the add operation inserts its value.
path: `/${let i: numberi}`, value: Schema.Jsonvalue: newValue: Schema.JsonnewValue[let i: numberi] })
}
return const patches: Array<JsonPatchOperation>patches
}
if (function isJsonObject(
value: unknown
): value is Schema.JsonObject
isJsonObject(oldValue: Schema.JsonoldValue) && function isJsonObject(
value: unknown
): value is Schema.JsonObject
isJsonObject(newValue: Schema.JsonnewValue)) {
const const keys1: string[]keys1 = var Object: ObjectConstructorProvides functionality common to all JavaScript objects.
Object.ObjectConstructor.keys(o: {}): string[] (+1 overload)Returns the names of the enumerable string properties and methods of an object.
keys(oldValue: Schema.JsonoldValue)
const const keys2: string[]keys2 = var Object: ObjectConstructorProvides functionality common to all JavaScript objects.
Object.ObjectConstructor.keys(o: {}): string[] (+1 overload)Returns the names of the enumerable string properties and methods of an object.
keys(newValue: Schema.JsonnewValue)
const const allKeys: string[]allKeys = var Array: ArrayConstructorArray.ArrayConstructor.from<string>(iterable: Iterable<string> | ArrayLike<string>): string[] (+3 overloads)Creates an array from an iterable object.
from(new var Set: SetConstructor
new <string>(iterable?: Iterable<string> | null | undefined) => Set<string> (+1 overload)
Set([...const keys1: string[]keys1, ...const keys2: string[]keys2])).Array<string>.sort(compareFn?: ((a: string, b: string) => number) | undefined): string[]Sorts an array in place.
This method mutates the array and returns a reference to the same array.
sort()
for (const const key: stringkey of const allKeys: string[]allKeys) {
const const esc: stringesc = function escapeToken(token: string): stringEscapes a JSON Pointer reference token according to RFC 6901 by encoding special characters so the token can be safely used as a segment in a JSON Pointer.
When to use
Use when you need to escape a single JSON Pointer path segment.
Details
- Returns a new escaped string
- Replaces
~ (tilde) with ~0 and / (forward slash) with ~1
- Returns the input unchanged if it contains no special characters
- Empty strings are valid and returned unchanged
Gotchas
The replacement order matters: ~ is replaced before / to prevent double-escaping.
Example (Escaping special characters)
import { JsonPointer } from "effect"
JsonPointer.escapeToken("a/b") // "a~1b"
JsonPointer.escapeToken("c~d") // "c~0d"
JsonPointer.escapeToken("path/to~key") // "path~1to~0key"
escapeToken(const key: stringkey)
const const path: stringpath = `/${const esc: stringesc}`
const const hasKey1: booleanhasKey1 = var Object: ObjectConstructorProvides functionality common to all JavaScript objects.
Object.ObjectConstructor.hasOwn(o: object, v: PropertyKey): booleanDetermines whether an object has a property with the specified name.
hasOwn(oldValue: Schema.JsonoldValue, const key: stringkey)
const const hasKey2: booleanhasKey2 = var Object: ObjectConstructorProvides functionality common to all JavaScript objects.
Object.ObjectConstructor.hasOwn(o: object, v: PropertyKey): booleanDetermines whether an object has a property with the specified name.
hasOwn(newValue: Schema.JsonnewValue, const key: stringkey)
if (const hasKey1: booleanhasKey1 && const hasKey2: booleanhasKey2) {
const const patch: JsonPatchconst patch: {
length: number;
toString: () => string;
toLocaleString: { (): string; (locales: string | string[], options?: Intl.NumberFormatOptions & Intl.DateTimeFormatOptions): string };
concat: { (...items: Array<ConcatArray<JsonPatchOperation>>): Array<JsonPatchOperation>; (...items: Array<JsonPatchOperation | ConcatArray<JsonPatchOperation>>): Array<JsonPatchOperation> };
join: (separator?: string) => string;
slice: (start?: number, end?: number) => Array<JsonPatchOperation>;
indexOf: (searchElement: JsonPatchOperation, fromIndex?: number) => number;
lastIndexOf: (searchElement: JsonPatchOperation, fromIndex?: number) => number;
every: { (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => value is S, thisArg?: any): this is readonly S[]; (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOp…;
some: (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => unknown, thisArg?: any) => boolean;
forEach: (callbackfn: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => void, thisArg?: any) => void;
map: (callbackfn: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => U, thisArg?: any) => Array<U>;
filter: { (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => value is S, thisArg?: any): Array<S>; (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) =>…;
reduce: { (callbackfn: (previousValue: JsonPatchOperation, currentValue: JsonPatchOperation, currentIndex: number, array: ReadonlyArray<JsonPatchOperation>) => JsonPatchOperation): JsonPatchOperation; (callbackfn: (previousValue: JsonPatchOperatio…;
reduceRight: { (callbackfn: (previousValue: JsonPatchOperation, currentValue: JsonPatchOperation, currentIndex: number, array: ReadonlyArray<JsonPatchOperation>) => JsonPatchOperation): JsonPatchOperation; (callbackfn: (previousValue: JsonPatchOperatio…;
find: { (predicate: (value: JsonPatchOperation, index: number, obj: ReadonlyArray<JsonPatchOperation>) => value is S, thisArg?: any): S | undefined; (predicate: (value: JsonPatchOperation, index: number, obj: ReadonlyArray<JsonPatchOperation>) =…;
findIndex: (predicate: (value: JsonPatchOperation, index: number, obj: ReadonlyArray<JsonPatchOperation>) => unknown, thisArg?: any) => number;
entries: () => ArrayIterator<[number, JsonPatchOperation]>;
keys: () => ArrayIterator<number>;
values: () => ArrayIterator<JsonPatchOperation>;
includes: (searchElement: JsonPatchOperation, fromIndex?: number) => boolean;
flatMap: (callback: (this: This, value: JsonPatchOperation, index: number, array: Array<JsonPatchOperation>) => U | ReadonlyArray<U>, thisArg?: This | undefined) => Array<U>;
flat: (this: A, depth?: D | undefined) => Array<FlatArray<A, D>>;
at: (index: number) => JsonPatchOperation | undefined;
findLast: { (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => value is S, thisArg?: any): S | undefined; (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation…;
findLastIndex: (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => unknown, thisArg?: any) => number;
toReversed: () => Array<JsonPatchOperation>;
toSorted: (compareFn?: ((a: JsonPatchOperation, b: JsonPatchOperation) => number) | undefined) => Array<JsonPatchOperation>;
toSpliced: { (start: number, deleteCount: number, ...items: Array<JsonPatchOperation>): Array<JsonPatchOperation>; (start: number, deleteCount?: number): Array<JsonPatchOperation> };
with: (index: number, value: JsonPatchOperation) => Array<JsonPatchOperation>;
}
patch = function get(
oldValue: Schema.Json,
newValue: Schema.Json
): JsonPatch
Computes a structural patch that transforms oldValue into newValue.
When to use
Use to compute a JSON Patch from before and after JSON documents, detect
structural changes, or create deterministic update operations.
Details
Generates a structural diff between two JSON values, producing a patch that
yields newValue when applied to oldValue. It returns an empty array when
values are identical, recursively diffs nested structures, emits root
replace operations for primitive changes, and processes object keys in
sorted order for stable output.
Gotchas
Arrays are compared by index position, with no move or copy detection. Array
removals are emitted from highest to lowest index to prevent index shifting.
The output is deterministic but not guaranteed to be minimal.
Example (Computing object diff)
import { JsonPatch } from "effect"
const oldValue = { users: [{ id: 1, name: "Alice" }], count: 1 }
const newValue = { users: [{ id: 1, name: "Bob" }, { id: 2, name: "Charlie" }], count: 2 }
const patch = JsonPatch.get(oldValue, newValue)
// [
// { op: "replace", path: "/users/0/name", value: "Bob" },
// { op: "add", path: "/users/1", value: { id: 2, name: "Charlie" } },
// { op: "replace", path: "/count", value: 2 }
// ]
get(oldValue: Schema.JsonoldValue[const key: stringkey], newValue: Schema.JsonnewValue[const key: stringkey])
for (const const op: JsonPatchOperationop of const patch: JsonPatchconst patch: {
length: number;
toString: () => string;
toLocaleString: { (): string; (locales: string | string[], options?: Intl.NumberFormatOptions & Intl.DateTimeFormatOptions): string };
concat: { (...items: Array<ConcatArray<JsonPatchOperation>>): Array<JsonPatchOperation>; (...items: Array<JsonPatchOperation | ConcatArray<JsonPatchOperation>>): Array<JsonPatchOperation> };
join: (separator?: string) => string;
slice: (start?: number, end?: number) => Array<JsonPatchOperation>;
indexOf: (searchElement: JsonPatchOperation, fromIndex?: number) => number;
lastIndexOf: (searchElement: JsonPatchOperation, fromIndex?: number) => number;
every: { (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => value is S, thisArg?: any): this is readonly S[]; (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOp…;
some: (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => unknown, thisArg?: any) => boolean;
forEach: (callbackfn: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => void, thisArg?: any) => void;
map: (callbackfn: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => U, thisArg?: any) => Array<U>;
filter: { (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => value is S, thisArg?: any): Array<S>; (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) =>…;
reduce: { (callbackfn: (previousValue: JsonPatchOperation, currentValue: JsonPatchOperation, currentIndex: number, array: ReadonlyArray<JsonPatchOperation>) => JsonPatchOperation): JsonPatchOperation; (callbackfn: (previousValue: JsonPatchOperatio…;
reduceRight: { (callbackfn: (previousValue: JsonPatchOperation, currentValue: JsonPatchOperation, currentIndex: number, array: ReadonlyArray<JsonPatchOperation>) => JsonPatchOperation): JsonPatchOperation; (callbackfn: (previousValue: JsonPatchOperatio…;
find: { (predicate: (value: JsonPatchOperation, index: number, obj: ReadonlyArray<JsonPatchOperation>) => value is S, thisArg?: any): S | undefined; (predicate: (value: JsonPatchOperation, index: number, obj: ReadonlyArray<JsonPatchOperation>) =…;
findIndex: (predicate: (value: JsonPatchOperation, index: number, obj: ReadonlyArray<JsonPatchOperation>) => unknown, thisArg?: any) => number;
entries: () => ArrayIterator<[number, JsonPatchOperation]>;
keys: () => ArrayIterator<number>;
values: () => ArrayIterator<JsonPatchOperation>;
includes: (searchElement: JsonPatchOperation, fromIndex?: number) => boolean;
flatMap: (callback: (this: This, value: JsonPatchOperation, index: number, array: Array<JsonPatchOperation>) => U | ReadonlyArray<U>, thisArg?: This | undefined) => Array<U>;
flat: (this: A, depth?: D | undefined) => Array<FlatArray<A, D>>;
at: (index: number) => JsonPatchOperation | undefined;
findLast: { (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => value is S, thisArg?: any): S | undefined; (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation…;
findLastIndex: (predicate: (value: JsonPatchOperation, index: number, array: ReadonlyArray<JsonPatchOperation>) => unknown, thisArg?: any) => number;
toReversed: () => Array<JsonPatchOperation>;
toSorted: (compareFn?: ((a: JsonPatchOperation, b: JsonPatchOperation) => number) | undefined) => Array<JsonPatchOperation>;
toSpliced: { (start: number, deleteCount: number, ...items: Array<JsonPatchOperation>): Array<JsonPatchOperation>; (start: number, deleteCount?: number): Array<JsonPatchOperation> };
with: (index: number, value: JsonPatchOperation) => Array<JsonPatchOperation>;
}
patch) {
function prefixPathInPlace(
op: JsonPatchOperation,
parent: string
): void
prefixPathInPlace(const op: JsonPatchOperationop, const path: stringpath)
const patches: Array<JsonPatchOperation>patches.Array<JsonPatchOperation>.push(...items: JsonPatchOperation[]): numberAppends new elements to the end of an array, and returns the new length of the array.
push(const op: JsonPatchOperationop)
}
} else if (!const hasKey1: booleanhasKey1 && const hasKey2: booleanhasKey2) {
const patches: Array<JsonPatchOperation>patches.Array<JsonPatchOperation>.push(...items: JsonPatchOperation[]): numberAppends new elements to the end of an array, and returns the new length of the array.
push({ op: "add"op: "add", path: stringJSON Pointer to the target location. For arrays, the last token may be -
to append.
When to use
Use to identify where the add operation inserts its value.
path, value: Schema.Jsonvalue: newValue: Schema.JsonnewValue[const key: stringkey] })
} else if (const hasKey1: booleanhasKey1 && !const hasKey2: booleanhasKey2) {
const patches: Array<JsonPatchOperation>patches.Array<JsonPatchOperation>.push(...items: JsonPatchOperation[]): numberAppends new elements to the end of an array, and returns the new length of the array.
push({ op: "remove"op: "remove", path: stringJSON Pointer to the target location.
When to use
Use to identify which location the remove operation deletes.
path })
}
}
return const patches: Array<JsonPatchOperation>patches
}
const patches: Array<JsonPatchOperation>patches.Array<JsonPatchOperation>.push(...items: JsonPatchOperation[]): numberAppends new elements to the end of an array, and returns the new length of the array.
push({ op: "replace"op: "replace", path: stringJSON Pointer to the target location. Use "" to replace the root document.
When to use
Use to identify which location the replace operation overwrites.
path: "", value: Schema.Jsonvalue: newValue: Schema.JsonnewValue })
return const patches: Array<JsonPatchOperation>patches
}