Skip to content

Instantly share code, notes, and snippets.

@coderofsalvation
Last active March 17, 2022 19:42
Show Gist options
  • Select an option

  • Save coderofsalvation/61dd5c86b81e4ca6963ed0535bd806e7 to your computer and use it in GitHub Desktop.

Select an option

Save coderofsalvation/61dd5c86b81e4ca6963ed0535bd806e7 to your computer and use it in GitHub Desktop.
bless: 256 bytes mixins-alternative to underscore- & lodash πŸ’ͺ

bless()

256 bytes mixin-alternative for ALL js frameworks in the world FOREVER: function bless(πŸ’ͺ)

Chainable, eventful, rewindable, typesafe, curryable mixins = bless()
After being blessed Before

(b)less temporary variables, (b)less plumbing, less code 🀯

Sourcecode πŸ’—

var bless
bless = function(a,methods){
    if( !a || a.unbless ) return a
    a.__proto__ = { __proto__: a.__proto__ }
    var prot = a.__proto__
    prot.mixin = (fn,f) => prot[fn] = f
    prot.unbless = () => { a.__proto__ = a.__proto__._p; return a; }
    if( methods ) for( var i in methods ) prot[i] = methods[i]
    for( var i in bless ) prot[i] = bless[i].bind(a,a)
    return a
}
// actual mixins are omitted in this snippet

var _ = bless // (optional) for underscore & lodash lovers πŸ’—

Google Appscript Users: please see the bless.gs snippet below (works without prototype)

API πŸ‘Ύ

function returns description
bless( myvar ) bless adds mixins + generates schema from data
myvar.valid(f) bless checks if data violates the schema (if so, it'll call f)
myvar.rewind() bless rewind data back to original data
myvar.schema() schema export the (json) schema
myvar.get('foo.bar.flop',1) bless shorthand for if( myvar.foo && myvar.foo.bar && myvar.foo.bar.flop ){ .. }else{ .. } plumbing
myvar.set('foo.bar.flop',5) bless creates myvar.foo.bar.flop = 5 without plumbing
myvar.then( () => ... ) bless comfortable promise-like chaining
myvar.pluck(['foo']) bless returns an object with the specified keys ({foo:{..}}) without plumbing
myvar.omit(['foo']) bless returns an object without the specified keys ({}) without plumbing
myvar.clone() bless returns a clone of the object
myvar.map( f ) bless maps over arrays or object-keys and calls f(value,key)
myvar.push( o ) bless pushes element to array (converts o to array if o is object)
myvar.each( (v,k) => .. ) bless iterates over arrays or object-keys
myvar.each( (v,k,next) => next() ) promise iterates over arrays or object-keys (asynchronous)
myvar.eventemitter() bless adds .on(event,function) and .emit(event,value) eventbus functionality
myvar.unbless() original var removes blessings (mixins)

How does it work?

The idea is to organize functions around data (data as a framework if you will). Mixins give our data arms & legs πŸ’ͺ πŸ—²:

foo = {bar:1}                           // arrays, strings and functions can also be blessed
bless(foo)
var x = foo.get('foo.bar.flop.flap',3)  // will not crash on nonexisting key, but sets & defaults to 3

Custom mixins:

function execute(a){ 
    console.log(a)
    return a
}
foo.mixin('execute',execute)            // only add to foo
bless.mixin('execute',execute)          // global mixin

foo.clone()
   .execute()                           // prints {bar:1} to the console

now visit 140bytes and add your own mixins.

Objects? Arrays? Async? sync?

.each() and .map() to rule em all

With blessed πŸ’ͺ objects, you can map() and .each() both synchronously and asynchronously over Objects and Arrays:

var a = [1,2]
var b = {a:1,b:2}
bless(a)
bless(b)

a.each( (v,k) => console.log(k) )
b.each( (v,k) => console.log(k) )
a.each( (v,k,next) => console.log(k); next() )

Byebye zillion ways to write async & sync loops, promises & async/await's

Install

  1. Just copy/paste minified-all.js into your project. DONE! πŸ’ͺ

Optionally you can copy/paste the bless-function above + minified-mixins.js (+1k) (below) in your project.

Eventable data

Turn data into event-busses like it's nothing. Especially for animation-, creative-, hotpluggable- or multitenant-code this prevents headaches & many lines of code:


var d = {a:1}
bless(d)
var em = d.eventemitter()
var unbind = d.on('foo',() => console.log("foo! ") )
d.emit('foo',23423234)
// call unbind() when done

Wait..how about debouncing certain events as well:

// add debouncer certain events
em.debounce = {'ui.update':300,'save':300}
bless.wrap( em, 'emit', (original,e,v) => {
    var d = em.debounce
    if( d[e] ){
        d.ids = d.ids || {}
        console.log("debouncing "+e)
        clearTimeout(d.ids[e])
        d.ids[e] = setTimeout( original, d[e], e, v)
    }else return original(e,v)
},em)

easy peasy!

// appscript version of bless()
// see https://coderofsalvation.github.io/bless
//
// appscript note: call .data() to get the data without the functions (because gs lacks __proto__ mutations)
//
function bless(o){
var _ = {}
_.unbless = function(obj){
for( var i in _ ) delete obj[i]
delete obj.events
delete obj.emit
delete obj.on
return obj
}
_.get = function get(obj,x,fallback) {
obj = obj || this
var o = String(x).split('.').reduce(function(acc, x) {
if (acc == null || acc == undefined || acc == ''){
return fallback;
}
return new Function("x","acc","return acc['" + x.split(".").join("']['") +"']" )(x, acc) || fallback
}, obj)
if( fallback && o == fallback ) _.set(obj,x,fallback)
obj.emit('get', {key:x,value:o})
return o
}
_.set = function set(obj, path, value) {
var last
var o = obj || this
path = String(path)
var vars = path.split(".")
var lastVar = vars[vars.length - 1]
vars.map(function(v) {
if (lastVar == v) return
o = (new Function("o","return o." + v)(o) || new Function("o","return o."+v+" = {}")(o))
last = v
})
new Function("o","v","o." + lastVar + " = v")(o, value)
obj.emit('set', {key:path,value:value})
return bless( obj || {} )
}
_.each = function(obj,f){
obj = obj || []
for( var i in obj ){
if( typeof obj[i] != 'function' ) f( obj[i], i )
}
return bless( obj || {} )
}
_.toArray = function(o){
if( o.push ) return o // already array
var y = []
for( var i in o ) y.push({key:i,value:o})
return bless(y)
}
_.clone = function(a){
return bless( JSON.parse( JSON.stringify(a || this) ) )
}
_.data = function(o){
return bless(o).clone().unbless() // return clone without blessed functions
}
_.xor = function(o, sources) {
var merge
merge = function(target, sources,opts) {
opts = opts || {}
function isObject(item) {
return (item && (typeof item === 'object' || typeof item == 'function') )
}
if (!sources.length) return target;
const source = sources.shift();
if (target && source ){
for (var key in source) {
var o = {}
if (isObject(source[key])) {
o[key] = {}
if (!target[key]) target[key] = o[key]
merge(target[key], [source[key]],opts);
} else {
target[key] = !opts.nonempty || source[key] ? source[key] : target[key]
}
}
}
return merge(target, sources,opts);
}
merge(o,sources,{nonempty:true})
return o
}
_.eventemitter = function(o){
o.events = {}
o.emit = function(e,val){
Logger.log("vv.emit('"+e+"')")
var evs = o.events[e] || []
evs.map( function(f){ if( f ) f(val) } )
return o
}
o.on = function(e,f){
var evs = o.events[e] || []
evs.push(f)
o.events[e] = evs
return o
}
}
_.then = function(a,f){
if( typeof f == "function" ){
if( f.then && !f.unbless ) return f.then(a)
f(a)
}
return a
}
_.mixin = function(o,fn,f){
o[fn] = function(){
o.emit(fn+':before',arguments)
f.apply(o,arguments)
o.emit(fn,arguments)
return o
}
return o
}
if( o && o.unbless ) return o // already blessed
for( var i in _ ) o[i] = _[i].bind(o,o)
o.eventemitter()
return o
}
"use strict";var _bless,_this3=void 0;function _typeof(t){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}(_bless=function(t){t.__proto__={__proto__:t.__proto__};var e=t.__proto__;for(var n in e.mixin=function(t,e){return nprot[t]=e},e.unbless=function(){return t.__proto__=t.__proto__._p,t},_bless)e[n]=_bless[n].bind(t,t);return t}).valid=function(t,e){var n=this,r=function(t){return JSON.stringify(t,null,2)},o=function(t){return JSON.parse(r(t).replace(/:[ ]?".*"/g,' : "string"').replace(/:[ ]?[0-9]+/g,' : "number"').replace(/:[ ]?(true|false)/g,': "boolean"'))},s=t.__proto__._schema?t.__proto__._schema:o(t);if(r(o(t))!=r(s)){var _="error:\n"+r(t)+"\ndoes not match schema:\n"+r(s);e&&e(_),console.log(_)}return t&&!t.__proto__._schema&&(console.log("added schema"),t.__proto__._data=JSON.parse(JSON.stringify(t)),t.__proto__._schema=s,t.__proto__.valid=function(){return _bless.bind(n,t)},t.__proto__.schema=function(){return t.__proto__._schema}),e&&(t.__proto__._schema=e),t},_bless.get=function(t,e,n){t=t||this;var r=String(e).split(".").reduce(function(e,r){return null==e||null==e?(_bless.set(t,r,n),n):new Function("x","acc","return acc['"+r.split(".").join("']['")+"']")(r,e)||n},t);return r||!t.__proto__.parent||n||(r=_bless.get(t.__proto__.parent,e)),r&&!r.unbless&&((r=_bless(r)).__proto__.parent=t),r},_bless.set=function(t,e,n){var r=t||this,o=(e=String(e)).split("."),s=o[o.length-1];return o.map(function(t){s!=t&&(r=new Function("o","return o."+t)(r)||new Function("o","return o."+t+" = {}")(r),t)}),new Function("o","v","o."+s+" = v")(r,n),t},_bless.pluck=function(t,e){var n=this,r={};return e.map(function(e){return r[e]=_bless.get(t||n,e)}),_bless(r)},_bless.omit=function(t,e){var n=t||this;return e.map(function(t){return delete n[t]}),_bless(n)},_bless.clone=function(t){return _bless(JSON.parse(JSON.stringify(t||this)))},_bless.rewind=function(t){for(var e in(t=t||_this3).__proto__._data)t[e]=t.__proto__._data[e];return t},_bless.eventemitter=function(t,e){t=t||this;var n=function(){this.events={}};n.prototype={emit:function(t){var e=[].slice.call(arguments,1);[].slice.call(this.events[t]||[]).filter(function(t){t.apply(null,e)})},on:function(t,e){if("function"!=typeof e)throw new Error("Listener must be a function");return(this.events[t]=this.events[t]||[]).push(e),function(){this.events[t]=this.events[t].filter(function(t){return t!==e})}.bind(this)}};var r=new n;t.mixin("emit",function(t,e){r.emit(t,e)}),t.mixin("on",function(t,e){return r.on(t,e)})},_bless.to,_bless.to=function(t,e){return _bless.to[e.name]?_bless.to[e.name](t):t},_bless.to.Array=function(t){if(t.filter)return t.unbless?t:_bless(t);if("object"==_typeof(t)){var e=[];return Object.keys(t).map(function(n){t[n].key=n,e.push(t[n])}),_bless(e)}return _bless("string"==typeof t?Array.from(t):[t])},_bless.to.Object=function(t){if("Object"==type.name){if(!t.length&&t.valueOf)return t.unbless?t:_bless(t);var e={};return t.map(function(t){return e[t.key]=t.data}),_bless(e)}},_bless.then=function(t,e){if(console.log("bless.then!"),"function"==typeof e){if(e.then&&!e.unbless)return e.then(t);e(t)}return t},_bless.map=function(t,e){var n=t.filter?t.unbless?t:_bless(t):t.unbless?t.to(Array):_bless(t).to(Array);return _bless(Array.prototype.map.call(n,e))},_bless.each=function(t,e,n){n=n||{};var r=t.filter?t.unbless?t:_bless(t):t.unbless?t.to(Array):_bless(t).to(Array),o=-1;r.length;if(!(e.length>2))return Array.prototype.map.call(t,e),t;var s=new Promise(function(t,s){var _;(_=function(i){try{if(i)throw i;if(++o>=r.length)return t();e(r[o],o,_)}catch(t){n.halterror?s(t):_()}})()});return _bless(s),delete s.__proto__.then,s.__proto__.parent=t,s},"undefined"!=typeof window&&(window.bless=_bless),"undefined"!=typeof module&&(module.exports=_bless);
var bless;(bless=function(e){e.__proto__={__proto__:e.__proto__};var t=e.__proto__;for(var n in t.mixin=((n,s)=>t[n]=s.bind(e,e)),t.unbless=(()=>(e.__proto__=e.__proto__._p,e)),bless)t[n]=bless[n].bind(e,e);return e}).valid=function(e,t){var n=e=>JSON.stringify(e,null,2),s=e=>JSON.parse(n(e).replace(/:[ ]?".*"/g,' : "string"').replace(/:[ ]?[0-9]+/g,' : "number"').replace(/:[ ]?(true|false)/g,': "boolean"')),r=e.__proto__._schema?e.__proto__._schema:s(e);if(n(s(e))!=n(r)){var o="error:\n"+n(e)+"\ndoes not match schema:\n"+n(r);t&&t(o),console.log(o)}return e&&!e.__proto__._schema&&(console.log("added schema"),e.__proto__._data=JSON.parse(JSON.stringify(e)),e.__proto__._schema=r,e.__proto__.valid=(()=>bless.bind(this,e)),e.__proto__.schema=(()=>e.__proto__._schema)),t&&(e.__proto__._schema=t),e},bless.get=function(e,t,n){e=e||this;var s=String(t).split(".").reduce(function(t,s){return null==t||null==t?(bless.set(e,s,n),n):new Function("x","acc","return acc['"+s.split(".").join("']['")+"']")(s,t)||n},e);return s||!e.__proto__.parent||n||(s=bless.get(e.__proto__.parent,t)),s&&!s.unbless&&((s=bless(s)).__proto__.parent=e),s},bless.set=function(e,t,n){var s=e||this,r=(t=String(t)).split("."),o=r[r.length-1];return r.map(function(e){o!=e&&(s=new Function("o","return o."+e)(s)||new Function("o","return o."+e+" = {}")(s),e)}),new Function("o","v","o."+o+" = v")(s,n),e},bless.pluck=function(e,t){var n={};return t.map(t=>n[t]=bless.get(e||this,t)),bless(n)},bless.omit=function(e,t){var n=e||this;return t.map(e=>delete n[e]),bless(n)},bless.clone=function(e){return bless(JSON.parse(JSON.stringify(e||this)))},bless.rewind=(e=>{for(var t in(e=e||this).__proto__._data)e[t]=e.__proto__._data[t];return e}),bless.eventemitter=function(e,t){e=e||this;var n=function(){this.events={}};n.prototype={emit:function(e){var t=[].slice.call(arguments,1);[].slice.call(this.events[e]||[]).filter(function(e){e.apply(null,t)})},on:function(e,t){if("function"!=typeof t)throw new Error("Listener must be a function");return(this.events[e]=this.events[e]||[]).push(t),function(){this.events[e]=this.events[e].filter(function(e){return e!==t})}.bind(this)}};var s=new n;e.mixin("emit",function(e,t){s.emit(e,t)}),e.mixin("on",function(e,t){return s.on(e,t)})},bless.to,bless.to=function(e,t){return bless.to[t.name]?bless.to[t.name](e):e},bless.to.Array=function(e){if(e.filter)return e.unbless?e:bless(e);if("object"==typeof e){var t=[];return Object.keys(e).map(n=>{e[n].key=n,t.push(e[n])}),bless(t)}return bless("string"==typeof e?Array.from(e):[e])},bless.to.Object=function(e){if("Object"==type.name){if(!e.length&&e.valueOf)return e.unbless?e:bless(e);var t={};return e.map(e=>t[e.key]=e.data),bless(t)}},bless.then=function(e,t){if(console.log("bless.then!"),"function"==typeof t){if(t.then&&!t.unbless)return t.then(e);t(e)}return e},bless.map=function(e,t){var n=e.filter?e.unbless?e:bless(e):e.unbless?e.to(Array):bless(e).to(Array);return bless(Array.prototype.map.call(n,t))},bless.each=function(e,t,n){n=n||{};var s=e.filter?e.unbless?e:bless(e):e.unbless?e.to(Array):bless(e).to(Array),r=-1;s.length;if(!(t.length>2))return Array.prototype.map.call(e,t),e;var o=new Promise((e,o)=>{var i;(i=function(l){try{if(l)throw l;if(++r>=s.length)return e();t(s[r],r,i)}catch(e){n.halterror?o(e):i()}})()});return bless(o),delete o.__proto__.then,o.__proto__.parent=e,o},"undefined"!=typeof window&&(window.bless=bless),"undefined"!=typeof module&&(module.exports=bless);
bless.valid=function(e,t){var n=e=>JSON.stringify(e,null,2),s=e=>JSON.parse(n(e).replace(/:[ ]?".*"/g,' : "string"').replace(/:[ ]?[0-9]+/g,' : "number"').replace(/:[ ]?(true|false)/g,': "boolean"')),r=e.__proto__._schema?e.__proto__._schema:s(e);if(n(s(e))!=n(r)){var o="error:\n"+n(e)+"\ndoes not match schema:\n"+n(r);t&&t(o),console.log(o)}return e&&!e.__proto__._schema&&(console.log("added schema"),e.__proto__._data=JSON.parse(JSON.stringify(e)),e.__proto__._schema=r,e.__proto__.valid=(()=>bless.bind(this,e)),e.__proto__.schema=(()=>e.__proto__._schema)),t&&(e.__proto__._schema=t),e},bless.get=function(e,t,n){e=e||this;var s=String(t).split(".").reduce(function(t,s){return null==t||null==t?(bless.set(e,s,n),n):new Function("x","acc","return acc['"+s.split(".").join("']['")+"']")(s,t)||n},e);return s||!e.__proto__.parent||n||(s=bless.get(e.__proto__.parent,t)),s&&!s.unbless&&((s=bless(s)).__proto__.parent=e),s},bless.set=function(e,t,n){var s=e||this,r=(t=String(t)).split("."),o=r[r.length-1];return r.map(function(e){o!=e&&(s=new Function("o","return o."+e)(s)||new Function("o","return o."+e+" = {}")(s),e)}),new Function("o","v","o."+o+" = v")(s,n),e},bless.pluck=function(e,t){var n={};return t.map(t=>n[t]=bless.get(e||this,t)),bless(n)},bless.omit=function(e,t){var n=e||this;return t.map(e=>delete n[e]),bless(n)},bless.clone=function(e){return bless(JSON.parse(JSON.stringify(e||this)))},bless.rewind=(e=>{for(var t in(e=e||this).__proto__._data)e[t]=e.__proto__._data[t];return e}),bless.eventemitter=function(e,t){e=e||this;var n=function(){this.events={}};n.prototype={emit:function(e){var t=[].slice.call(arguments,1);[].slice.call(this.events[e]||[]).filter(function(e){e.apply(null,t)})},on:function(e,t){if("function"!=typeof t)throw new Error("Listener must be a function");return(this.events[e]=this.events[e]||[]).push(t),function(){this.events[e]=this.events[e].filter(function(e){return e!==t})}.bind(this)}};var s=new n;e.mixin("emit",function(e,t){s.emit(e,t)}),e.mixin("on",function(e,t){return s.on(e,t)})},bless.to,bless.to=function(e,t){return bless.to[t.name]?bless.to[t.name](e):e},bless.to.Array=function(e){if(e.filter)return e.unbless?e:bless(e);if("object"==typeof e){var t=[];return Object.keys(e).map(n=>{e[n].key=n,t.push(e[n])}),bless(t)}return"string"==typeof e?bless(Array.from(e)):bless([e])},bless.to.Object=function(e){if("Object"==type.name){if(!e.length&&e.valueOf)return e.unbless?e:bless(e);var t={};return e.map(e=>t[e.key]=e.data),bless(t)}},bless.then=function(e,t){if(console.log("bless.then!"),"function"==typeof t){if(t.then&&!t.unbless)return t.then(e);t(e)}return e},bless.map=function(e,t){var n=e.filter?e.unbless?e:bless(e):e.unbless?e.to(Array):bless(e).to(Array);return bless(Array.prototype.map.call(n,t))},bless.each=function(e,t,n){n=n||{};var s=e.filter?e.unbless?e:bless(e):e.unbless?e.to(Array):bless(e).to(Array),r=-1;s.length;if(!(t.length>2))return Array.prototype.map.call(e,t),e;var o=new Promise((e,o)=>{var l;(l=function(i){try{if(i)throw i;if(++r>=s.length)return e();t(s[r],r,l)}catch(e){n.halterror?o(e):l()}})()});return bless(o),delete o.__proto__.then,o.__proto__.parent=e,o},"undefined"!=typeof window&&(window.bless=bless),"undefined"!=typeof module&&(module.exports=bless);
bless.valid = function(
a, // (optional) data object
b // (optional) schema
){
var stringify = (a) => JSON.stringify(a,null,2)
var schema = (a) => JSON.parse(
stringify(a)
.replace(/:[ ]?".*"/g,' : "string"')
.replace(/:[ ]?[0-9]+/g,' : "number"')
.replace(/:[ ]?(true|false)/g,': "boolean"')
)
var s = a.__proto__._schema ? a.__proto__._schema
: schema(a)
if( stringify(schema(a)) != stringify(s) ){
var err = "error:\n"+stringify(a)+"\ndoes not match schema:\n"+stringify(s)
if(b) b(err)
console.log(err)
}
if ( a && !a.__proto__._schema ){
console.log("added schema")
a.__proto__._data = JSON.parse(JSON.stringify(a))
a.__proto__._schema = s
a.__proto__.valid = () => bless.bind(this,a)
a.__proto__.schema = () => a.__proto__._schema // expose schema
}
if( b ) a.__proto__._schema = b // overwrite schema
return a
}
bless.get = function get(obj,x,fallback) {
obj = obj || this
var o = String(x).split('.').reduce(function(acc, x) {
if (acc == null || acc == undefined ){
bless.set(obj,x,fallback)
return fallback;
}
return new Function("x","acc","return acc['" + x.split(".").join("']['") +"']" )(x, acc) || fallback
}, obj)
if( !o && obj.__proto__.parent && !fallback) o = bless.get(obj.__proto__.parent,x) // search parent object
if( o && !o.unbless ){
o = bless(o)
o.__proto__.parent = obj //remember source object
}
return o
}
bless.set = function set(obj, path, value) {
var last
var o = obj || this
path = String(path)
var vars = path.split(".")
var lastVar = vars[vars.length - 1]
vars.map(function(v) {
if (lastVar == v) return
o = (new Function("o","return o." + v)(o) || new Function("o","return o."+v+" = {}")(o))
last = v
})
new Function("o","v","o." + lastVar + " = v")(o, value)
return obj//.unbless ? obj : bless(obj)
}
bless.pluck = function pluck(obj,arr){
var o = {}
arr.map( (l) => o[l] = bless.get(obj || this,l) )
return bless(o)
}
var am = ['push','filter','find']
am.map( (m) => {
bless[m] = function(method,obj,a,b,c){
var o = bless.to.Array(obj)
return bless( Array.prototype[m].call( o,a) )
}.bind(null,m)
})
bless.omit = function omit(obj,arr) {
var o = obj || this
arr.map((l) => delete o[l])
return bless(o)
}
bless.clone = function(a){
return bless( JSON.parse( JSON.stringify(a || this) ) )
}
bless.wrap = function wrap(obj, method, handler, context) {
var org = obj[method];
// Unpatch first if already patched.
if (org.unwrap) {
org = org.unwrap();
}
// Patch the function.
obj[method] = function() {
var ctx = context || this;
var args = [].slice.call(arguments);
args.unshift(org.bind(ctx));
return handler.apply(ctx, args);
};
// Provide "unpatch" function.
obj[method].unwrap = function() {
obj[method] = org;
return org;
};
// Return the original.
return org;
}
bless.rewind = (a) => {
a = a || this
for( var i in a.__proto__._data )
a[i] = a.__proto__._data[i]
return a
}
bless.eventemitter = function(data){
data = data || this
// credits: https://github.com/ai/nanoevents
var NanoEvents=function(){this.events={}};NanoEvents.prototype={emit:function(t){var n=[].slice.call(arguments,1);[].slice.call(this.events[t]||[]).filter(function(t){t.apply(null,n)})},on:function(t,n){if("function"!=typeof n)throw new Error("Listener must be a function");return(this.events[t]=this.events[t]||[]).push(n),function(){this.events[t]=this.events[t].filter(function(t){return t!==n})}.bind(this)}};
var em = new NanoEvents()
data.mixin('emit', function(e,v){ em.emit(e,v); return data; } )
data.mixin('on', function(e,f){ return em.on(e,f) } )
return em
}
bless.to
bless.to = function(a,type){
return bless.to[ type.name ] ? bless.to[type.name](a) : a
}
bless.to.Array = function(a){
if( a.pop ) return a.unbless ? a : bless(a) // already array
if( typeof a == "object" ){
var o = []
Object.keys(a).map( (k) => { a[k].key = k; Array.prototype.push.call(o,a[k]) } )
return bless(o)
}
return typeof a == "string" ? bless( Array.from(a) ) : bless([a])
}
bless.to.Object = function(a){
if( type.name == "Object" ){
if( ! a.length && a.valueOf ) return a.unbless ? a : bless(a) // already object
var o = {}
a.map( (v) => o[v.key] = v.data )
return bless(o)
}
}
bless.then = function(a,f){
/* *TODO*
return new Promise( (resolve,reject) => {
resolve( f(a) )
})
*/
if( typeof f == "function" ){
if( f.then && !f.unbless ) return f.then(a)
return f(a)
}
return a
}
bless.map = function(a,cb){
var b = a.pop ? ( a.unbless ? a : bless(a) )
: ( a.unbless ? a.to(Array) : bless(a).to(Array) )
return bless( Array.prototype.map.call(b,cb) )
}
/*
* _.each(arr_or_obj, cb, [next] ) (map with optional object & async support)
*
* calls cb(data, next) for each element in arr, and continues loop
* based on next()-calls (last element propagates done()).
* Perfect to iterate over an array synchronously, while performing async
* operations inbetween the elements.
*
* example: _.each([1, 2, 3], (data,key,next) => next(), optional: {halterror:true} )
* .then( ... )
*
*/
bless.each = function each(a,cb,opts) {
opts = opts || {}
var b = a.pop ? ( a.unbless ? a : bless(a) )
: ( a.unbless ? a.to(Array) : bless(a).to(Array))
var i = -1, length = b.length
var async = cb.length > 2
if( !async ){
Array.prototype.map.call( b, cb )
return a
}
var p = new Promise( (resolve,reject) => {
var f
f = function(err){
try{
if(err) throw err
i++
if( i >= b.length ) return resolve()
cb( b[i], i, f)
}catch (e){
opts.halterror ? reject(e) : f()
}
}
f()
})
bless(p)
delete p.__proto__.then // delete bless.then to prevent infinite then-loop
p.__proto__.parent = a // set parent, so get() works again
return p
}
if( typeof window != "undefined") window.bless = bless
if( typeof module != "undefined") module.exports = bless
/*
* USAGE
*
var data = { foo:[{a:1},{a:2}], b:1 }
bless(data)
data.set( 'bar.a.b', [] )
.get( 'foo' )
.each( (v,k) => data.bar.a.b.push(v.a) )
.get( 'bar.a.b' )
.map( (v,k) => v*=10 )
.each( (v,k) => console.log(v) )
.clone()
.each( (v,k,next) => {
fetch(`/endpoint?v=${v}`,{method:'POST'})
.then( (r) => r.json() )
.then( (j) => data.bar.a.b[k] = j )
.then( ( ) => next( ) )
.catch( (e) => next(e) )
},{halterror:false})
.then( ( ) => console.log(`done`) )
.catch( (e) => console.log(`oops: ${e}`) )
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment