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

mutation-tracker

v1.0.37

Published

Library that provides means to tracks mutation in JSON objects.

Readme

Mutation Tracker 1.0

Mutation-Tracker is a new library to associate and track metadata to properties within JSON objects within an independent mirror object tree.

Why Mutation Tracker?

By associating and managing metadata in a mirro object to properties of JSON objects we can:

  • Track changes to a JSON objects, by registering the changes to properties
  • Track how many times some properties are mutated and maintain statistics for those properties in the JSON object
  • Avoid writing boiler plate code for every new JSON object type.

Usage

Consider the following example where we have a complex JSON object and for every property in this object we want to associate a flag to represent whether the property value has ever changed or not.


// sample JSON object
var user = {
	name: {
		firstname: "John",
		lastname: "Doe"
	},
	role: [
		"admin"
	]
	address: "123 Main Street"
}

Below is how we would use mutation-tracker to initialize a tracker instance for our User object. The great thing about mutation-tracker is that it can auto generate internal state using the object type provided at the time of initialization. Also, below we have used boolean as type of metadata (mutation-descriptor).

Mutation descriptor is information/tag that is associated to each mutated or non-mutated property. We can use other data types such as number, date, string, etc for mutation descriptor type.


// initialize tracker using 'boolean' as mutation descriptor type
var tracker = MutationTracker<typeof user, boolean>(user, {
  defaultValue: false
});

Once a tracker instance is initialized, it internally creates and manages a mirrored state that mimics the structure of the User object and looks as below:


//	var user = {
//		name: {
//			firstname: false,
//			lastname: false
//		},
//		role: [
//			false
//		],
//		address: false
//	}

Below is how we update the tracker for a change in value of a property "name.firstname":


// set `name.firstname` property as mutated by setting a boolean descriptor as true.
tracker.setMutatedByAttributeName(true, "name.firstname");

// The updated state within mutation-tracker will now be:
//	var user = {
//		name: {
//			firstname: true,
//			lastname: false
//		},
//		role: [
//			false
//		],
//		address: false
//	}

// the mutation `state` information can be accessed as below:

var mutation = tracker.state.name?.firstname;

console.log("is firstname mutated? ", mutation);

check out the npm package form-runner that uses mutation-tracker to implement unopinionated front-end form validation library.

How to Use Mutation-Tracker For an HTML Form?

Consider the HTML below:

In a browser:

<input type="text" id="firstname" />
<input type="text" id="lastname" />
<textarea id="address"></textarea>

The JavaScript object below represents the state of a HTML form above:

var user = {
	name: {
		firstname: "John",
		lastname: "Doe"
	},
	address: "123 Main Street"
}

To track changes in the object above, we can track the property changes as follows:


// Import the mutation library reference.
import { MutationTracker } from "./mutation-tracker";

// Create a new instance of mutation-tracker with it's own state.
var tracker = MutationTracker(user, { defaultValue: false });

// set name.firstname property as mutated
tracker.setMutatedByAttributeName(true, "name.firstname");

console.log(JSON.stringify(tracker.state));
// { name: { firstname: true, lastname: false }, address: false }

// Add a new property of type array.
tracker.setMutatedByAttributeName(true, "roles[0]");

console.log(JSON.stringify(tracker.state));
// { name: { firstname: true, lastname: false }, roles: [ true ], address: false }

Examples

Below are a few example that shows some but not all of the potential uses of mutation-tracker library.

1 - Initialization with an existing object

var tracker = MutationTracker(user, { defaultValue: false });
console.log(JSON.stringify(tracker.state));
// { name: { firstname: false, lastname: false }, address: false }

2 - Initialization with an empty object

var tracker = MutationTracker({}, { defaultValue: false });
console.log(JSON.stringify(tracker.state));
// {}

3 - Set mutation in an existing object

var tracker = MutationTracker(user, { defaultValue: false });
tracker.setMutatedByAttributeName(true, "name.firstname");
console.log(JSON.stringify(tracker.state));
// { name: { firstname: true, lastname: false }, address: false }

4 - Set mutation in an empty object

var tracker = MutationTracker({}, { defaultValue: false });
tracker.setMutatedByAttributeName(true, "name.firstname");
console.log(JSON.stringify(tracker.state));
// { name: { firstname: true }

5 - Set mutation at initialization

var tracker = MutationTracker({}, {
	defaultValue: false, 
	initialMutation: {
		mutatedAttributes: [
			"name.firstname",
			"name.lastname"
		],
		mutatedValue: true
	}
});
console.log(JSON.stringify(tracker.state));
// { name: { firstname: true, lastname: true }, address: false }

6 - Set multiple mutations

var tracker = MutationTracker(user, { defaultValue: false });
tracker.setMutatedByAttributeNames(true, [
	"name.firstname",
	"name.lastname"
]);
console.log(JSON.stringify(tracker.state));
// { name: { firstname: true, lastname: true }, address: false }

7 - Check mutation of an attribute

var tracker = MutationTracker(user, { defaultValue: false });
tracker.setMutatedByAttributeNames(true, [
	"name.firstname",
	"name.lastname"
]);
console.log("firstname: ", tracker.getMutatedByAttributeName("name.firstname"));
console.log("address: ", tracker.getMutatedByAttributeName("address"));
// firstname: true
// address: false

8 - Set all attributes as mutated

var tracker = MutationTracker(user, { defaultValue: false });
tracker.setAll(true);
console.log(JSON.stringify(tracker.state));
// { name: { firstname: true, lastname: true }, address: true }

9 - Reset mutations on all attributes

var tracker = MutationTracker({}, {
	defaultValue: false,
	initialMutation: {
		mutatedAttributes: [
			"name.firstname"
		],
		mutatedValue: true
	}
});
console.log(JSON.stringify(tracker.state));
// { name: { firstname: true, lastname: false }, address: false }
tracker.setMutatedByAttributeName(true, "name.lastname");
console.log(JSON.stringify(tracker.state));
// { name: { firstname: true, lastname: true }, address: false }
tracker.reset();
console.log(JSON.stringify(tracker.state));
// { name: { firstname: true, lastname: false }, address: false }

10 - Clear mutations on all attributes

var tracker = MutationTracker({}, {
	defaultValue: false, 
	initialMutation: {
		mutatedAttributes: [
			"name.firstname"
		],
		mutatedValue: true
	}
});
console.log(JSON.stringify(tracker.state));
// { name: { firstname: true, lastname: false }, address: false }

tracker.setMutatedByAttributeName(true, "name.lastname");
console.log(JSON.stringify(tracker.state));
// { name: { firstname: true, lastname: true }, address: false }

tracker.clear();
console.log(JSON.stringify(tracker.state));
// { name: { firstname: false, lastname: false }, address: false }

11 - Add mutation tracking of a new attribute

var tracker = MutationTracker(user, { defaultValue: false });
console.log(JSON.stringify(tracker.state));
// { name: { firstname: false, lastname: false }, address: false }

tracker.setMutatedByAttributeName(true, "age");
tracker.setMutatedByAttributeName(true, "role[0]");
tracker.setMutatedByAttributeName(true, "role[1]");

console.log(JSON.stringify(tracker.state));
// { name: { firstname: false, lastname: false }, age: true, role [ true, true ], address: false }

12 - Using number mutation descriptor

var tracker = MutationTracker<number>(user, { defaultValue: 0 });
tracker.setMutatedByAttributeName(100, "name.firstname");
tracker.setMutatedByAttributeName(200, "name.lastname");
console.log(JSON.stringify(tracker.state));
// { name: { firstname: 100, lastname: 200 }, address: 0 }

Documentation

MutationTracker

below is the list of functions and properties available with mutation-tracker.

| Members | Type | Description | | ------------ | ----- | ------------ | | MutationTracker<T, Values>(target: Values, config: MutationConfig) | constructor | Create tracker instance | | setMutatedByAttributeName() | function | sets mutation flag for a qualified attribute name | | setMutatedByAttributeNames() | function | sets mutation flag for multiple qualified attribute names | | getMutatedByAttributeName() | function | gets mutation flag for a qualified attribute name | | reset() | function | Sets mutation tracking back to the initialized state such as reapplying initial mutation settings | | setAll() | function | Sets mutation for tracked attributes to true | | clear() | function | For tracking Without Type, removes all mutation tracking. For tracking with a Type, sets all mutations to default value | | initiallyMutatedAttributes | readonly property | Returns list of qualified attribute names, initially set as mutated | | initiallyMutatedValue | readonly property | Returns value set for initially mutated qualified attribute names | | state | readonly property | Returns object that represents current state of tracked mutations |

MutationConfig

below is the list of properties avaiable on configuration object to initialize mutation-tracker.

| Property/Function | Description | | ------------ | ------------ | | initialMutation | configuration for initial mutation | | initialMutation.mutatedAttributes | list of qualified attribute names, initially set as mutated | | initialMutation.mutatedValue | value set for initially mutated qualified attribute names | | defaultValue | Default value set when functions MutationTracker.resetAll() or MutationTracker.clear() are called |