https://github.com/momsfriendlydevco/chainable
Tiny, zero-dependency chainable object wrapper
https://github.com/momsfriendlydevco/chainable
Last synced: 6 months ago
JSON representation
Tiny, zero-dependency chainable object wrapper
- Host: GitHub
- URL: https://github.com/momsfriendlydevco/chainable
- Owner: MomsFriendlyDevCo
- License: mit
- Created: 2024-09-04T00:41:23.000Z (almost 2 years ago)
- Default Branch: master
- Last Pushed: 2024-12-20T06:30:19.000Z (over 1 year ago)
- Last Synced: 2025-12-22T06:01:48.956Z (7 months ago)
- Language: JavaScript
- Size: 81.1 KB
- Stars: 1
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
@MomsFriendlyDevCo/Chainable
============================
Make any JavaScript object a chainable, functional interface.
This library is _intentionally_ tiny and dependency free. The entire library, minified is less than 1kb!
**Make the tiny Mitt event library chainable**
```javascript
import chainable from '../lib/chainable.js';
import mitt from 'mitt';
let emitter = chainable(mitt)
.on('blarp', ()=> { /* Handle blarp emit */ })
.on('flonk', ()=> { /* Handle flonk emit */ })
.emit('blarp')
.value() // Get original unwrapped emitter
```
**Make a browser DOM element chainable**
```javascript
import chainable from '@momsfriendlydevco/chainable';
// Make a chainable DOM object
chainable(document.createElement('div'));
.addEventListener('click', ()=> { /* Handle clicks */ })
.set('style.position', 'absolute') // Set a deeply nested property
.value() // Output the original object (if needed)
```
Why?
----
This library exists this because handling chainability in some non-chainable interfaces gets repetitive.
```javascript
// Horrible
setup using the native DOM
let widget = document.createElement('div');
widget.addEventListener('click', ()=> { /* Handle click */ });
widget.style.position = 'absolute';
widget.style.top = '0px';
widget.style.left = '0px';
widget.classList.add('red');
document.body.append(widget);
```
```javascript
// Equivalent using chainable
document.append(
chainable(document.createElement('div'));
.addEventListener('click', ()=> { /* Handle clicks */ })
.set('style.position', 'absolute') // Set a deeply nested property
.set('style.top', '0px')
.set('style.left', '0px')
.call('classList.add', 'red')
.value() // Output the original raw DOMElement
);
```
API
===
chainable(object)
-----------------
Create a new chainable instance.
This also sets `$source` to the original object.
chainable.$source
-----------------
Also available as `chainable.source` if there isn't any conflict with the name.
The chainable source object.
Generally you don't want to access this directly.
chainable.$call(name, ...args)
------------------------------
Also available as `chainable.call(name, ...args)` if there isn't any conflict with the name.
As with `.$get` the name can be in dotted notation or array notation for deeply nested methods.
Call a method on source but ignore the response and return the chainable instance.
chainable.$set(key, val)
------------------------
Also available as `chainable.set(key, val)` if there isn't any conflict with the name.
Set one or more properties within a source object.
Can be called as a simple key/val setter - `chainable.$set(keyName, value)` - or as an object - `chainable.$set({key1: val1, key2: val2})`
The key can also use dotted notation (e.g. `this.is.a.nested.key`) or an array notation (e.g. `['this', 'is', 'a', 'nested', 'key']`) to set deeply nested properties.
Returns the chainable instance.
chainable.$get(path)
--------------------
Also available as `chainable.get(path)` if there isn't any conflict with the name.
Fetch a value from the source object, returning it.
The path can also use dotted notation (e.g. `this.is.a.nested.key`) or an array notation (e.g. `['this', 'is', 'a', 'nested', 'key']`) to get deeply nested properties.
Returns the value found at the path or undefined if none.
chainable.$value()
------------------
Also available as `chainable.value()` if there isn't any conflict with the name.
Return the original source object - i.e. unwrap the original.
chainable.$tap(callback)
------------------------
Also available as `chainable.tap(callback)` if there isn't any conflict with the name.
Run a callback inline as `(chainable) => { /* handler */ }`, ignore the result and return the chainable instance.
chainable.$thru(callback)
-------------------------
Also available as `chainable.tap(callback)` if there isn't any conflict with the name.
Run a callback inline as `(chainable) => { /* handler */ }`, take the returned value as the new `$source` and and return the chainable instance.
chainable.$replace(newState)
----------------------------
Replace the target item if it looks like an object
This is really only used when overwriting internal state or possibly replacing the state object due to a `$thru()` or `$call` return.
Returns the chainable instance.