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

typed-patch

v0.2.11

Published

Type-aware object patch

Readme

Software Plumbers Typed Patch

The type-aware object patch utility.

Tl;DR

let patch = Patch.compare(object1, object2);

let object3 = patch.apply(object2)

and object3 should equal object1.

If any of the properties and sub-properties of object1 are themselves classes, and have a static method fromJSON somewhere in their prototype chain, then this fromJSON method will be applied to the result of merging properties betweem the appropriate sub-trees in order to create an object of the correct class.

Arrays are merged with an LCS diff algorithm, preserving sort order. ES6 Map objects are merged using an ordered join which may result in a different order of elements in the resulting maps (the result will always be sorted by key).

The utility has more subtle and feature-rich ways of specifying types, and doing things like deciding the type of array elements and specifying how arrays are merged. If interested, read on.

For the latest API documentation see The Software Plumbers Site

Project Status

Alpha. It seems functional, and the unit tests pass. The basic API is settling down.

Why another diff/patch utility?

This one is aware of object types and potential polymorphism in the patch. That is to say, that the object tree that results from applying a patch to an object may contain objects of different classes to those which were in the patch object or indeed to those in the original patched object.

Many other diff/patch utilities also create rather verbose patches; the JSON pointer specification (RFC6901) is admirable but its use as a basis for a patch format is questionable. If each leaf that differs in the tree must be identified by its full path from the root (per JSONP) then in deeply nested object trees the property names nearer the root appear many times in the resulting diff. This diff creates a hierarchical diff format that is concise and reasonably easy to read.

Type Awareness

When merging properties between the patched object and the patch, the resulting property can either be a straight object (in which case, no problem) or an instance of a class. To create an instance of the class, the patch algorithm needs to know what kind of object to create.

Encoding types in the diff format is an option which we have rejected due to the implications of allowing data transmitted over the wire to specify a class name that the data will be converted into.

This problem is closely related to the issue of re-creating object trees from JSON delivered across the wire or from document stores like Mongo. This may be why there are so many diff utilities - they are usually bound to a particular way of doing things.

By default, typed-patch therefore derives type information entirely from the object to be patched. This can be achieved most simply by putting a static method fromJSON in the base class of any typed property. This method is used to covert untyped properties into an instance of the required object class.

This works in many cases, but not when the patch contains properties that do not exist in the patched object. In this case, we need to implement a getAttrProps static method which takes a name argument and returns an object containing a factory method (elementFactory) or an object type elementType suitable for populating the property of that name.

Array and Map properties

In the case of array and map properties, getAttrProps may also return the following metadata:

  • collectionElementType the type of elements in the array
  • collectionElementFactory a factor object for creating new array elements
  • sorted defines if a map can be assumed to be sorted by its key (avoiding a re-sort)
  • map determines if an array can be treated as a map. If so, the additional properties below are needed
  • key a function that can extract a unique ID from the array element (e.g. e=>e.id)
  • value a function that can extract a value from the array element (e.g. to e=>e)
  • entry a function that can construct a array element from a key/value pair (e.g. (k,v)=>v)
  • keyComparator a comparator object for comparing keys, required if key values cannot be compared with >,<,===

Maps are diffed and merged by comparing a sorted lists of key values; the order of maps may not be preserved in the merge operation. Arrays are diffed using an LCS algorithm, unless the 'map' option is true in which case they are diffed as Maps using the values extracted by the key and value functions.