Home

🍦 @fizzwiz/vanilla

Lightweight semantics for working with plain JavaScript objects

@fizzwiz/vanilla is a small, dependency‑free library that adds semantic structure to everyday JavaScript objects. It focuses on clarity, safety, and intent, providing higher‑level abstractions for configuration storage, deep object navigation, coercion, and validation — while staying very close to plain JSON data and native objects.

Rather than introducing new data models or DSLs, Vanilla works with what you already have, making object traversal and input handling more expressive and predictable.

The library is designed to be useful both in:

  • Application code (configuration, request handling, domain logic)
  • Low‑level tooling where introducing heavy frameworks would be undesirable

✨ Features

OptionStore

  • Store options keyed by types / classes rather than strings
  • Automatically resolve options by walking up the prototype chain
  • Ideal for defaults, policies, and behavioral configuration in class hierarchies

ObjNavigator

A semantic cursor over an object tree with a unified failure model.

  • get(expr) — retrieve a value or compute one from the current scope
  • set(path, value) — assign a value (optionally creating missing nodes)
  • delete(path) — remove a property
  • select(predicate) — filter object entries in place
  • coerce(path, fn, opts) — coerce a value safely
  • validate(expr, predicate, opts) — validate values with configurable failure behavior
  • within(expr) / without() — scoped navigation across derived objects

All operations share a unified failure model. Each step may specify how failures are handled using the opts argument:

  • onError — run a callback
  • errorEvent — emit an event
  • bubbles — bubble the error to parent navigators
  • throws — throw immediately
  • payload — control the emitted / thrown value

Once a navigator enters a failed state, subsequent operations become no‑ops unless explicitly handled.


📦 Installation

NPM

npm install @fizzwiz/vanilla

Browser (UMD bundle via jsDelivr)

<script src="https://cdn.jsdelivr.net/npm/@fizzwiz/vanilla/dist/vanilla.bundle.js"></script>
<script>
  const { OptionStore, ObjNavigator } = window.vanilla;

  const nav = ObjNavigator.from({})
    .set('user.profile.name', 'Alice'); 
</script>

🚀 Quick Start

import { OptionStore, ObjNavigator } from '@fizzwiz/vanilla';

// OptionStore example
class Base {}
class Derived extends Base {}

const options = OptionStore.as({});
options.set(Base, 'color', 'blue');
options.get(Derived, 'color'); // 'blue'

// ObjNavigator example
const nav = ObjNavigator.from({})
  .set('user.profile', {})  
  .with('user.profile')    
    .set('name', 'Alice')
    .set('age', 30)
  .without() 

🧭 DOM Navigation Example

ObjNavigator is not limited to JSON data. Because navigation steps can be functions, it can traverse derived or computed structures such as the DOM.

Navigating the DOM with querySelector

<div id="app">
  <section class="profile">
    <span class="name">Alice</span>
    <span class="age">30</span>
  </section>
</div>

const { ObjNavigator } = window.vanilla;

const name = ObjNavigator.from(document)
  .with(doc => doc.querySelector('#app .profile .name'))
  .get('textContent');

console.log(name); // 'Alice'


🛂 Request / Handler Example (Coerce + Validate)

A common use case is handling untrusted input (e.g. HTTP query parameters), where errors should be reported, not thrown. In such cases, it is useful to emit an error event or handle the failure immediately through a dedicated callback.

import { ObjNavigator } from '@fizzwiz/vanilla';

function handleRequest(req, res) {

  const nav = ObjNavigator.from({ ...req.query })
    .on('inputError', () => res.status(400).send('Malformed query'))
    .coerce('limit', Number, { errorEvent: 'inputError' })
    .validate('limit', v => Number.isInteger(v) && v > 0, { errorEvent: 'inputError' });

  if (nav.failed) return; // response already sent

  // ✅ Safe, validated input
  // Business logic here
}

In this model:

  • coerce() converts input without throwing
  • validate() enforces invariants
  • Errors are emitted as events, not thrown
  • Business logic only runs if input is known to be valid

🧠 Mental Model

  • An ObjNavigator is a cursor over a value

  • Each step either:

    • Produces a new value, or
    • Transitions into a failed state
  • Failure handling is explicit and composable (callbacks, events, bubbling, throws)

This makes navigation, validation, and transformation linear, readable, and intention‑revealing.


🌐 Documentation & Resources


📄 License

MIT