🍦 @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 scopeset(path, value)— assign a value (optionally creating missing nodes)delete(path)— remove a propertyselect(predicate)— filter object entries in placecoerce(path, fn, opts)— coerce a value safelyvalidate(expr, predicate, opts)— validate values with configurable failure behaviorwithin(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 callbackerrorEvent— emit an eventbubbles— bubble the error to parent navigatorsthrows— throw immediatelypayload— 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 throwingvalidate()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
- Blog: https://vanilla.blog.fizzwiz.cloud
- GitHub Pages: https://fizzwiz.github.io/vanilla
📄 License
MIT