npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

simple-object-patcher

v0.0.1

Published

Simple RFC6902 object patcher, with options

Readme

simple-object-patcher

RFC6902 (JSON Patch) apply and diff, with the options a live-state application tends to need: replacing the document at its root, patching destructively or into a clone, creating the parents an add needs, and an error that says which part of the patch failed and whether anything was written before it did.

It is a thin layer over rfc6902: that package does the patching, this one wraps it.

Installation

npm install simple-object-patcher

ESM only, no build step.

Usage

import { applyPatch, createPatch, PatchError } from "simple-object-patcher";

const state = { headline: "old" };

applyPatch(state, [{ op: "replace", path: "/headline", value: "new" }]);
// state is now { headline: "new" }

createPatch({ a: 1 }, { a: 2 });
// [{ op: "replace", path: "/a", value: 2 }]

applyPatch(document, patch, options?)

Applies patch (an array of RFC6902 operations) and returns the patched document. By default it mutates document in place and returns that same object.

| Option | Default | Effect | | --- | --- | --- | | nest | true | Allows the patch to replace the document at its root, with path: "" | | immutable | false | Clones the document and patches the clone, leaving the original alone | | create | true | Creates the missing parent objects an add needs |

Parts are applied one at a time, in order, and the first failure throws. Parts before the failure have already been applied; parts after it are not attempted.

nest

RFC6902 cannot replace a document at its root, because there is no parent to assign to. With nest the document is put inside a wrapper, the patch paths are rewritten against it, and the wrapper's contents are returned — so a whole-document replace works:

applyPatch({ a: 1 }, [{ op: "replace", path: "", value: { b: 2 } }]);
// { b: 2 }

A root replace necessarily returns a different object than the one passed in, since it is a new value rather than a mutation. Every other operation still mutates in place and returns the original reference. Set nest: false to patch the document directly and reject root-level operations.

immutable

const before = { a: 1 };
const after = applyPatch(before, [{ op: "add", path: "/b", value: 2 }], { immutable: true });
// before is still { a: 1 }, after is { a: 1, b: 2 }

A null or undefined document is treated as {}, so a state that does not exist yet can be patched into being rather than throwing:

applyPatch(undefined, [{ op: "add", path: "/a", value: 1 }], { immutable: true });
// { a: 1 }

create

RFC6902 requires the parent of an add to exist. With create, the parents are built first, so a nested value can be set without walking the object into place by hand:

applyPatch({}, [{ op: "add", path: "/a/b/c", value: 1 }]);
// { a: { b: { c: 1 } } }

applyPatch({}, [{ op: "add", path: "/a/b/c", value: 1 }], { create: false });
// throws PatchError

createPatch(document1, document2)

Returns the patch that turns document1 into document2, or [] if they are already equal. This is rfc6902's createPatch unchanged, re-exported so callers do not need to depend on both packages.

const patch = createPatch(before, after);
applyPatch(before, patch, { immutable: true }); // deep-equals after

PatchError

Thrown when a part of the patch cannot be applied. Beyond message, it carries:

  • patch — the single operation that failed. With nest on (the default) its path is the rewritten one, prefixed with the wrapper key.
  • mutated — whether a non-test operation had been attempted before the throw, meaning the document may already have been changed. A patch that fails on a leading test reports false.
try {
    applyPatch(state, patch);
}
catch(error) {
    if(error instanceof PatchError && error.mutated)
        // the document is in a partly-patched state; reload it rather than trusting it
}

mutated is deliberately pessimistic: it reports that a write was attempted, not that it succeeded.

Tests

npm test

License

MIT