@bybrave/fast-json-patch2
v4.0.0
Published
Maintained fork of fast-json-patch — RFC-6902 JSON Patch with observe/compare, now with a modern exports map, dual ESM+CJS, built-in types, a Date/toJSON compare fix and 0 dependencies
Maintainers
Readme
@bybrave/fast-json-patch2
Maintained fork of fast-json-patch — a fast RFC-6902 JSON-Patch implementation with observe/compare (diff) support — with a modern exports map, dual ESM+CJS, built-in TypeScript types, a Date/toJSON compare fix and 0 dependencies.
The original package has ~30M downloads/month and no release since 2022. Its package.json has no exports field (so named ESM imports and modern bundlers break) and compare/observe shred Date values into char-by-char patches. This fork keeps the RFC-6902 apply path byte-for-byte (verified against the official JSON-Patch conformance suite) and fixes the packaging and diff bugs.
npm install @bybrave/fast-json-patch2// CommonJS
const jsonpatch = require('@bybrave/fast-json-patch2');
// ESM — named imports now work
import { applyPatch, compare, observe, generate } from '@bybrave/fast-json-patch2';
// TypeScript types built inThe Date bug, and how it is fixed
compare and observe clone the document through JSON.stringify, which turns a Date into an ISO string. The live object still holds the Date, so the diff walks a string against an object and emits one add per character:
// original [email protected]
compare({ when: new Date('2024-01-01') }, { when: new Date('2024-06-15') });
// [ {op:'add', path:'/when/0', value:'2'}, {op:'add', path:'/when/1', value:'0'}, … ] 💥This fork treats any value exposing toJSON (Date, luxon DateTime, Decimal.js, …) as an atomic leaf and diffs it by its serialized form:
// @bybrave/fast-json-patch2
compare({ when: new Date('2024-01-01') }, { when: new Date('2024-06-15') });
// [ { op: 'replace', path: '/when', value: '2024-06-15T00:00:00.000Z' } ]
compare({ t: new Date('2024-01-01') }, { t: new Date('2024-01-01') });
// [] — equal dates, no spurious patchThe apply path is untouched, so this changes nothing about how patches are applied — only how compare/observe generate them.
Fixes over [email protected]
| Fixed | Original issue |
|---|---|
| No exports map → named ESM imports and bundlers (parcel, webpack 5) fail | #310, #317, #311, #129, #323 |
| compare/observe shred Date / toJSON values into char-by-char patches | #325, #272, #278, #318, #332, #183 |
| ESM delivered via a sed-based build script | — (replaced with tsup) |
| Empty-string key ("") round-trip, undefined-source diff — regression-tested | #260, #280 |
| escapePathComponent / unescapePathComponent public and typed | #173 |
By design (documented, not changed)
compareis a positional array diff — inserting into an array can produce a cascade ofreplaceops. The patch is valid and applies correctly; minimal (LCS) array diffing is out of scope (#215, #282).- No
movegeneration incompare(#91);observekeeps dirty-checking, not Proxy (#96). - The RFC-6902 operation logic, JSON-Pointer handling and the
banPrototypeModificationssecurity guard are preserved exactly.
Migrating from fast-json-patch
- const jsonpatch = require('fast-json-patch');
+ const jsonpatch = require('@bybrave/fast-json-patch2');The API is identical. Named ESM imports that used to fail now work:
import { applyPatch, compare } from '@bybrave/fast-json-patch2';If you diff documents containing Date values, compare/observe now produce clean replace ops instead of char-by-char patches — no code change needed on your side.
API
// Apply
jsonpatch.applyPatch(document, patch); // returns { newDocument, … }
jsonpatch.applyOperation(document, operation);
jsonpatch.applyReducer(document, operation, index); // reducer signature
jsonpatch.getValueByPointer(document, '/a/b');
// Validate
jsonpatch.validate(patch, document?); // returns JsonPatchError | undefined
// Diff & observe
jsonpatch.compare(objA, objB); // Operation[]
const observer = jsonpatch.observe(document);
jsonpatch.generate(observer); // Operation[] since last generate
jsonpatch.unobserve(document, observer);
// JSON-Pointer helpers
jsonpatch.escapePathComponent('a/b'); // 'a~1b'
jsonpatch.unescapePathComponent('a~1b'); // 'a/b'Support
If this package saves you time, you can support maintenance:
Bitcoin (BTC): bc1q37557q5jpeaxqydzwvf3jgj7zhnfpn2td3q40q
Credits & license
MIT. Based on fast-json-patch by Joachim Wester.
