moonpatch

    Guarded rollback receipts for RFC 6902 JSON Patch transactions in MoonBit.

    json-patch
    json-pointer
    rollback
    rfc6902
    rfc6901
    Download zip
    Version
    0.2.0
    License
    Apache-2.0
    Last updated
    23 days ago
    Downloads
    32

    No dependencies

    #MoonPatch

    简体中文 | English · GitHub · Mooncakes

    MoonPatch is a MoonBit library and CLI for reversible JSON Patch transactions. Given a JSON document and an RFC 6902 patch, apply_with_receipt returns the new value, affected paths, and a standard RFC 6902 rollback patch. The rollback begins with a test of the exact result: if anything changed since the receipt was created, undo fails without changing the caller's document.

    Version 0.1.0 implemented the six standard patch operations and RFC 6901 pointers. These are existing ecosystem functionality, including in forey217/moonconfig. Version 0.2.0 adds an operation-aware, guarded rollback workflow for patches supplied by a caller or configuration tool. MoonPatch can consume a patch produced by moonconfig; it does not copy moonconfig's source or implement its diff and merge workflow. See ecosystem comparison and provenance.

    #Try a reversible change

    Install MoonBit and Node.js 24, then run from the repository root:

    moon run cmd/main --target js -- --compact --receipt examples/service-config.json examples/service-config.patch.json

    The output has value (updated JSON), rollback (standard patch with a leading test) and paths (affected pointers). Save value and rollback as separate JSON files, then run moon run cmd/main --target js -- --compact value.json rollback.json to restore the original. --receipt is optional; without it the CLI emits only the updated document. On Windows, ./scripts/moon.ps1 wraps a local or installed moon executable.

    Public APIs: apply_with_receipt(document, patch) -> PatchReceipt, apply(document, patch) -> Json, apply_with_receipt_json(document_text, patch_text), apply_json, RFC 6901 pointer helpers and structured diagnostics. examples/library executes a change and rollback using only the public API. Module name: JingLan0v0/moonpatch; see Mooncakes for published versions.

    #Behavior and limits

    • Forward patches support add, remove, replace, move, copy, and test in order, including array insertion, - append, root replacement, and escaped pointer tokens.
    • Input JSON is immutable from the caller's perspective. Failure reports PatchError with code, operation index, path, and message; no partial result is returned.
    • Rollback steps run in reverse order. For move, the smallest shared ancestor is restored to account for index shifts; receipts can be larger than forward patches.
    • Maximum 4,096 operations for apply and 4,095 for apply_with_receipt (one slot is needed for the guard). Pointers are limited to 16,384 characters and 128 tokens. CLI inputs are limited to 16 MiB each; in-memory output and receipt size are not bounded by that input limit.
    • The current target is MoonBit JS. Node.js handles only CLI file/stdin/stdout. There is no diff generator, merge engine, JSON Schema validator, HTTP client, or deletion of the entire root.

    The root test checks JSON value equality, not provenance, caller identity, or an external concurrency lock. Persistent or concurrent systems still need their own storage transaction and authorization policy.

    #Reproducible evidence

    Run node scripts/verify.mjs for formatting, compilation, unit tests, the public library example, three CLI scenarios with round-trip rollback, CLI process tests, and the pinned json-patch-tests suite. All 108 enabled upstream cases pass locally; four disabled upstream cases are reported separately. The three scenarios cover service configuration, release ordering, and access policy. GitHub Actions runs on Windows and Ubuntu. Results for a specific commit are recorded in acceptance evidence.

    Apache-2.0. See third-party notices for test-vector and infrastructure provenance.

    PatchError

    pub(all) suberror PatchError {
    PatchError(Diagnostic)
    }

    Diagnostic

    pub(all) struct Diagnostic {
    code : String
    operation : Int
    path : String
    message : String
    }

    A stable diagnostic for invalid patches or paths.

    PatchReceipt

    pub(all) struct PatchReceipt {
    value : Json
    rollback : Json
    paths : Array[String]
    }

    A successful transaction and a guarded RFC 6902 patch that reverses it. The rollback's first operation tests the entire result, so it refuses to overwrite a document that has changed since this receipt was produced.

    apply

    fn apply(document : Json, patch : Json) -> Json raise PatchError

    Apply all six RFC 6902 operations in order. On error, no result is returned and the original Json value remains unchanged.

    apply_json

    fn apply_json(document_text : String, patch_text : String) -> Json raise PatchError

    Parse JSON text and apply a patch, reporting invalid JSON explicitly.

    apply_with_receipt

    fn apply_with_receipt(document : Json, patch : Json) -> PatchReceipt raise PatchError

    Apply an RFC 6902 patch and create an operation-aware rollback receipt. The receipt supports at most 4095 input operations because its rollback needs one additional guard operation within the 4096-operation limit.

    apply_with_receipt_json

    fn apply_with_receipt_json(document_text : String, patch_text : String) -> Json raise PatchError

    escape_pointer_token

    fn escape_pointer_token(token : String) -> String

    Escape one object key for inclusion in a JSON Pointer.

    format_pointer

    fn format_pointer(tokens : Array[String]) -> String raise PatchError

    Build a bounded RFC 6901 pointer from already-decoded object keys or array index tokens. The empty token list addresses the document root.

    json_equal

    fn json_equal(left : Json, right : Json) -> Bool

    Compare JSON values by RFC 6902 value semantics, including numeric value equality and object key order independence.

    parse_pointer

    fn parse_pointer(path : String) -> Array[String] raise PatchError

    Decode an RFC 6901 JSON Pointer. The empty string selects the root. URI fragment identifiers such as #/a are intentionally not accepted.

    pointer_get

    fn pointer_get(document : Json, path : String) -> Json raise PatchError

    Retrieve the value selected by an RFC 6901 pointer.

    receipt_json

    fn receipt_json(receipt : PatchReceipt) -> Json

    Serialize a receipt for CLI users without introducing a second patch format. rollback is an ordinary RFC 6902 patch for apply.

    version

    fn version() -> String