Skip to content

editorstack/json_patch

Repository files navigation

json_patch

A Dart implementation of JSON Pointer (RFC 6901), JSON Patch (RFC 6902), and JSON Merge Patch (RFC 7396). Its behavior and deterministic diff output match Rust json-patch 4.2.0.

Features

  • All JSON Patch operations: add, remove, replace, move, copy, and test.
  • Transactional patching with rollback, plus an explicit unsafe partial-application API.
  • JSON Merge Patch and deterministic positional diff generation.
  • Immutable typed operations with dart_mappable JSON serialization.
  • Structured errors carrying the failed operation, path, reason, and document state.
  • Strict JSON and JSON Pointer validation.

JSON Patch

JsonPatch.applyPatch mutates JSON maps and lists in place where possible and returns the resulting root. Always retain the return value because a root-level operation can replace the document entirely.

import 'dart:convert';

import 'package:json_patch/json_patch.dart';

Object? document = jsonDecode('[{"name":"Andrew"},{"name":"Maxim"}]');
final patch = Patch.fromJson([
  {'op': 'test', 'path': '/0/name', 'value': 'Andrew'},
  {'op': 'add', 'path': '/0/happy', 'value': true},
]);

document = JsonPatch.applyPatch(document, patch);

Patch text can be decoded and encoded directly:

final patch = Patch.fromJsonString(
  '[{"op":"replace","path":"/title","value":"Hello"}]',
);
final encoded = patch.toJsonString();

Operations can also be constructed with typed paths:

final patch = Patch([
  AddOperation(path: JsonPointer.parse('/tags/-'), value: 'dart'),
  RemoveOperation(path: JsonPointer.parse('/obsolete')),
]);

JsonPatch.applyPatch is transactional. If an operation fails, prior changes are rolled back and a PatchException is thrown. JsonPatch.applyPatchUnsafe skips rollback; its exception's document field contains the partially modified root, including after root replacement.

try {
  document = JsonPatch.applyPatch(document, patch);
} on PatchException catch (error) {
  document = error.document;
  print('Operation ${error.operation} failed at ${error.path}: ${error.kind}');
}

Merge patch

document = {'title': 'Goodbye', 'obsolete': true};
document = JsonPatch.applyMergePatch(document, {
  'title': 'Hello',
  'obsolete': null,
});

As required by RFC 7396, a null object member removes that member, while a non-object patch replaces the whole document.

Diff

final generated = JsonPatch.diff(
  {'title': 'Goodbye', 'tags': ['example', 'sample']},
  {'title': 'Hello', 'tags': ['example']},
);

final updated = JsonPatch.applyPatch(
  {'title': 'Goodbye', 'tags': ['example', 'sample']},
  generated,
);

The diff algorithm intentionally matches Rust json-patch: objects follow input map order, arrays are compared positionally, and generated patches do not synthesize move or copy. Exact operation ordering on Rust requires serde_json's preserve_order feature.

JSON values and platform compatibility

Documents and operation values must contain only null, booleans, finite numbers, strings, lists, and string-keyed maps. Inserted values are deeply copied, so patch and document collections never alias one another.

For Rust compatibility, integer 1 and floating-point 1.0 compare as different JSON values. Exact numeric interoperability targets the Dart VM. The package remains web-compatible, but Dart web cannot exactly represent integers outside JavaScript's 53-bit safe range.

Input documents must use mutable maps and lists if an operation modifies them. Values produced by jsonDecode satisfy this requirement.

Conformance

The test suite includes every enabled upstream JSON Patch, rollback, and JSON Merge Patch fixture, plus exact error-string checks. The implementation is also cross-checked against Rust for identical diff serialization and cross-runtime patch results.

License and attribution

This package is a Dart port of Ivan Dubrov's json-patch and is available under either the MIT License or Apache License 2.0, at your option.

About

No description, website, or topics provided.

Resources

License

Unknown and 2 other licenses found

Licenses found

Unknown
LICENSE
Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages