
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
generate-json-patch
Advanced tools
A simple function to diff any two objects and generate a JSON Patch
Create RFC 6902 compliant JSON Patch objects based on two given JSON objects with a configurable interface.
objectHash to match array elementspropertyFilterarray.ignoreMove)maxDepth to collapse deep trees into a single replaceWorks on node and browser environments.
npm install generate-json-patch
import { generateJSONPatch } from 'generate-json-patch';
const before = {
manufacturer: 'Ford',
model: 'Granada',
year: 1972,
colors: ['red', 'silver', 'yellow'],
engine: [
{ name: 'Cologne V6 2.6', hp: 125 },
{ name: 'Cologne V6 2.0', hp: 90 },
{ name: 'Cologne V6 2.3', hp: 108 },
{ name: 'Essex V6 3.0', hp: 138 },
],
};
const after = {
manufacturer: 'Ford',
model: 'Granada',
year: 1974,
colors: ['red', 'silver', 'yellow'],
engine: [
{ name: 'Essex V6 3.0', hp: 138 },
{ name: 'Cologne V6 2.6', hp: 125 },
{ name: 'Cologne V6 2.3', hp: 108 },
{ name: 'Cologne V6 2.0', hp: 90 },
],
};
const patch = generateJSONPatch(before, after);
console.log(patch);
// [
// { op: 'replace', path: '/year', value: 1974 },
// { op: 'move', from: '/engine/3', path: '/engine/0' },
// ]
generateJSONPatch(before, after, config?) accepts the options below. The examples reuse the same payload shown in the Usage section.
objectHashMatch array elements by a stable hash instead of position. Useful to detect moves and edits for arrays of objects.
import { generateJSONPatch, type JsonValue, type ObjectHashContext, pathInfo } from 'generate-json-patch';
const before = {
manufacturer: 'Ford',
model: 'Granada',
year: 1972,
colors: ['red', 'silver', 'yellow'],
engine: [
{ name: 'Cologne V6 2.6', hp: 125 },
{ name: 'Cologne V6 2.0', hp: 90 },
{ name: 'Cologne V6 2.3', hp: 108 },
{ name: 'Essex V6 3.0', hp: 138 },
],
};
const after = {
manufacturer: 'Ford',
model: 'Granada',
year: 1974,
colors: ['red', 'silver', 'yellow'],
engine: [
{ name: 'Essex V6 3.0', hp: 138 },
{ name: 'Cologne V6 2.6', hp: 125 },
{ name: 'Cologne V6 2.3', hp: 108 },
{ name: 'Cologne V6 2.0', hp: 90 },
],
};
const patch = generateJSONPatch(before, after, {
objectHash(value: JsonValue, context: ObjectHashContext) {
const { length, last } = pathInfo(context.path);
if (length === 2 && last === 'engine') {
// keep engine comparisons stable by model name
// @ts-expect-error JsonValue does not guarantee shape
return value?.name;
}
// default to position for other arrays
return context.index.toString();
},
});
console.log(patch);
// [
// { op: 'replace', path: '/year', value: 1974 },
// { op: 'move', from: '/engine/3', path: '/engine/0' },
// ]
propertyFilterSkip properties when diffing. Return false to ignore a field.
const before = {
manufacturer: 'Ford',
model: 'Granada',
year: 1972,
vin: 'secret-123',
};
const after = {
manufacturer: 'Ford',
model: 'Granada',
year: 1974,
vin: 'secret-456',
};
const patch = generateJSONPatch(before, after, {
propertyFilter(propertyName) {
return propertyName !== 'vin';
},
});
console.log(patch);
// [
// { op: 'replace', path: '/year', value: 1974 }
// ]
array.ignoreMovePrevent move operations if order does not matter to you. The resulting patch will not reorder arrays.
const before = {
manufacturer: 'Ford',
model: 'Granada',
year: 1972,
engine: [
{ name: 'Cologne V6 2.6', hp: 125 },
{ name: 'Cologne V6 2.0', hp: 90 },
{ name: 'Cologne V6 2.3', hp: 108 },
{ name: 'Essex V6 3.0', hp: 138 },
],
};
const after = {
manufacturer: 'Ford',
model: 'Granada',
year: 1972,
engine: [
{ name: 'Essex V6 3.0', hp: 138 },
{ name: 'Cologne V6 2.6', hp: 125 },
{ name: 'Cologne V6 2.3', hp: 108 },
{ name: 'Cologne V6 2.0', hp: 90 },
],
};
const unorderedPatch = generateJSONPatch(before, after, {
objectHash: (value: any) => value.name,
array: { ignoreMove: true },
});
console.log(unorderedPatch);
// []
maxDepthStop descending deeper than a given path depth. When the limit is reached, a replace is emitted for that subtree.
const before = {
manufacturer: 'Ford',
model: 'Granada',
year: 1972,
specs: {
trim: 'Base',
colorOptions: ['red', 'silver', 'yellow'],
},
};
const after = {
manufacturer: 'Ford',
model: 'Granada',
year: 1974,
specs: {
trim: 'Ghia',
colorOptions: ['red', 'silver', 'yellow'],
},
};
const patch = generateJSONPatch(before, after, { maxDepth: 2 });
console.log(patch);
// [
// {
// op: 'replace',
// path: '/specs',
// value: { trim: 'Ghia', colorOptions: ['red', 'silver', 'yellow'] },
// },
// { op: 'replace', path: '/year', value: 1974 },
// ]
Both config functions (objectHash, propertyFilter) receive a context as the second parameter to drive fine-grained decisions:
side: 'left' | 'right' indicating the value being inspectedpath: JSON Pointer-style path to the current valueindex: only on objectHash, giving the array index being processedSee the objectHash example above for how pathInfo can be combined with the context to scope hashing logic.
When ignoreMove is false, array reorders emit move operations instead of delete/add pairs. We minimize moves by:
objectHash to get stable identifiers.{ op: 'move', from, path } operations needed to reach the target sequence.This is implemented in move-operations.ts (longestCommonSequence + moveOperations) and is exercised in the tests in src/move-operations.spec.ts.
For more examples, check out the tests
FAQs
A simple function to diff any two objects and generate a JSON Patch
We found that generate-json-patch demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.