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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@wonderlandlabs/forestry

v3.0.28

Published

State Management System in Javascript

Downloads

249

Readme

Mutators

There is two ways to update a branch:

  1. "assert" a concrete value by calling myTree.next(value)
  2. "mutate" a $tree by passing a function that will change the $tree's value. This can have a second parameter if you want, referred to as the "seed".

Why would you not just want to cram assertions in? well... if you inject a function and a value, you'll use less memory over time - the value will come into and through the function and only be cached in the topmost branch. This means even if your store has an extensive history, the only thing that will use up storage space is the parameters you pass in. (There are some benchmarking caches that will persist longer if you use ittermittent caching)

In many situations this is not going to be a huge issue but why be wasteful? If you have a long term scenario (say a game) flooding your store with large historical memory is not ideal. Say you have a game with a spaceship that can go up, down, left or right and you have a spaceship object

{
    name: 'mySpaceship',
    inventory: ['yams', 'copper', 'alien babes'],
    x: 0,
    y: 0,
}

You could move by doing this:


function moveUp($tree: TreeIF<Spaceship>) {
    $tree.next ({...$tree.value, y: $tree.value.y + 1})
}

but that would leave a full record of the spaceship in each branch and that is a lot of wasted store. If instead, you called


function moveUp($tree: TreeIF<Spaceship>) {
    $tree.mutate(({value} : {value: Spaceship | undefined }) => {
        if (!value) return makeNewSpaceship();
        return  ({...value, y: value.y + 1})
    })
}

then the spaceship is created by returning a variation of the previous branch's value. There is a technical possiblity that if the mutator is the first branch in the $tree (the "root") there will be no previous value - but if you insure an inital value in the constructor this doesn't acutally happen.

Is this value cached? "yes but" only the topmost branch keeps a local copy of its output; (more detail in README.caching.md)

Mutators are lazy

until the $tree (and its top.value) are retrieved the mutator is not called. So it may never genreate a mutated value, cache locally, etc. If you subscribe to the $tree, of course, its value will be called continuously. but if for some reason you do not, it may be some time before the value is retrieved and the first time it is, it may take some time. Technically JS can nest thousands of calls, but if this is a concern, check out itermittent cachinng. This will "bake" a mutator every few branches so the callback queue is never too long. (more detail in README.caching.md)

The Seed

Sometimes you want to add a parameter to the mutator; in Redux this would be a "payload." .mutate(mutator, seed, name) takes an argument that you can pass into the mutator, as in


function move ({value, seed} : {value: Spaceship | undefined, seed: Point }) {
        if (!value) return makeNewSpaceship(seed);
        const {x, y} = seed;
        return  ({...value, x: value.x + x, y: value.y + y})
    }

function moveUp($tree: TreeIF<Spaceship>, x, y) {
    $tree.mutate(move, {x, y})
}

Your seed will be preserved in the history of branches, so try not to pass seeds which are complex or memory consumptive.

Naming your mutators

There is an optional third argument, a name string; its optional but if you want more insight into your branches' history you can label the mutator with a name that is viewable if you iterate through your $tree with .forEachUp((branch, count) => {...}) or .forEachDown(...).

If you name the mutator function as above its name will be used in the logging.