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

vana

v0.5.9

Published

Observe your immutable state trees

Downloads

34

Readme

npm Build status codecov Bundle size Code style: Prettier Donate

Observe your immutable state trees.

Vana adds observability to normal objects without mutating their public appearance. The only exception to that rule is that all objects are made immutable. This is Vana at its core.

 

Read the introduction.

 

Basic usage

import { o } from 'vana'

let state = o({
  /* Any data can go here */
})

The returned state is immutable and observable.

Before we make any changes, let's observe our state object:

import { tap } from 'vana'

// This callback is called synchronously whenever `state` changes.
tap(state, newState => {
  state = newState
})

The first kind of mutation passes a callback to the revise function. Any changes made within the callback are used to create an immutable copy of our state object.

import { revise } from 'vana'

const base = state
const copy = revise(state, draft => {
  /* Mutate our immutable state in here */
})

assert(base !== copy)
assert(copy === state) // Our `state` variable is updated.

The copy object is now observed by whoever was observing the base object, and revising the base object is now forbidden.

The second kind of mutation passes an object to the revise function. This is essentially the Object.assign of Vana.

const copy = revise(state, {
  /* Any data can go here */
})

Those are the basics. Here is a sandbox you can play with:

https://codesandbox.io/s/z33pzx31wp

https://github.com/alloc/vana-sandbox

 

Install

yarn add vana

 

Integrations

 

Advanced usage

Here are some advanced use cases.

Cloning an observable object

Clone an observable object by passing it to the o function.

const base = o({ a: 1 })
const copy = o(base)

// The "copy" has its own observable identity.
assert(isObservable(copy))
assert(base !== copy)

// The "base" is still observable and revisable.
assert(isObservable(base))
tap(base, console.log)
revise(base, { a: 2 })

 

Controlled observables

Pass a callback to the o function to create a controlled observable.

// This pattern is great for memoized subscriptions.
const foo = o<number>(next => {
  next(0) // Always provide an initial value.
  let n = 0
  let id = setInterval(() => next(++n), 1000)
  return () => clearInterval(id)
})
// Log every new value.
foo.tap(console.log)

 

The latest function

Give any value and receive the latest revision (if possible), else return it as-is.

const o1 = o({ foo: true })
const o2 = revise(o1, { foo: false })
const o3 = revise(o2, { foo: true })

assert(o1 !== o3)
assert(latest(o1) === o3)

// Trash in, trash out
assert(latest(1) === 1)

 

The keepAlive function

Use the keepAlive function to make a "living" object out of an observable object. The returned object is a mirror of the observable's current value.

import { keepAlive } from 'vana'

let initialState = o({ a: 1 })
let state = keepAlive(initialState)

// The latest revision is always reflected
const lastState = revise(initialState, { a: 2 })
assert(state.a === 2)

// Can be passed to `latest`
assert(latest(state) === lastState)

// Be sure to call dispose when appropriate
state.dispose()

 

The watch function

This function lets you watch any property path in a state tree.

import { watch } from 'vana'

// An observable that updates when `obj.a.b.c` is changed
const prop = watch(obj).a.b.c

// Run a function when the property value is changed
const observer = prop.tap(console.log)

// Get the current property value
prop.get()

// Shallow properties can be observed more efficiently
const prop = watch(obj, 'a')

// You can use a selector function if you want
const prop = watch(obj, obj => obj.a.b.c)

Every property in the path is observed.

The property value is deeply observed if possible.

 

Array helpers

These functions are for working with immutable arrays. Each function works for any array regardless of mutability. They always return a modified copy of the given array (or the given array if no changes were made).

import { append, prepend, insert, concat, remove } from 'vana'

// Append one or more values to a copy of the given array.
append(arr, ...values)

// Prepend one or more values to a copy of the given array.
prepend(arr, ...values)

// Insert one or more values into a copy of the given array.
insert(arr, index, ...values)

// Merge one or more arrays into a copy of the given array.
concat(arr, ...values)

// Remove one or more values from a copy of the given array.
remove(arr, index, (count = 1))

 

Custom immutable classes

Any class can be made compatible with Vana's cloning logic.

import { immerable, o, revise, keepAlive, latest } from 'vana'

class Foo {
  readonly bar: number = 0

  // Let `Foo` instances be assumed readonly
  static [immerable] = true

  // Mutate yourself with `revise`
  setBar(bar: number) {
    return revise(this, { bar })
  }
}

let foo = o(new Foo())
assert(Object.isFrozen(foo))
assert(foo.bar === 0)

foo = foo.setBar(1)
assert(foo.bar === 1)

// works with `keepAlive`
const fooLatest = keepAlive(foo)

const foo3 = foo.setBar(2)
assert(foo3 !== foo)
assert(foo3.bar === 2)
assert(fooLatest.bar === 2)

// and with `latest`
foo = latest(foo)
assert(foo === foo3)

 

TODO: Provide more advanced use cases