"use strict"; /* * $asyncbind has multiple uses, depending on the parameter list. It is in Function.prototype, so 'this' is always a function * * 1) If called with a single argument (this), it is used when defining an async function to ensure when * it is invoked, the correct 'this' is present, just like "bind". For legacy reasons, 'this' is given * a memeber 'then' which refers to itself. * 2) If called with a second parameter ("catcher") and catcher!==true it is being used to invoke an async * function where the second parameter is the error callback (for sync exceptions and to be passed to * nested async calls) * 3) If called with the second parameter===true, it is the same use as (1), but the function is wrapped * in an 'Promise' as well bound to 'this'. * It is the same as calling 'new Promise(this)', where 'this' is the function being bound/wrapped * 4) If called with the second parameter===0, it is the same use as (1), but the function is wrapped * in a 'LazyThenable', which executes lazily and can resolve synchronously. * It is the same as calling 'new LazyThenable(this)' (if such a type were exposed), where 'this' is * the function being bound/wrapped */ function processIncludes(includes,input) { var src = input.toString() ; var t = "return "+src ; var args = src.match(/.*\(([^)]*)\)/)[1] ; var re = /['"]!!!([^'"]*)['"]/g ; var m = [] ; while (1) { var mx = re.exec(t) ; if (mx) m.push(mx) ; else break ; } m.reverse().forEach(function(e){ t = t.slice(0,e.index)+includes[e[1]]+t.substr(e.index+e[0].length) ; }) ; t = t.replace(/\/\*[^*]*\*\//g,' ').replace(/\s+/g,' ') ; return new Function(args,t)() ; } var $asyncbind = processIncludes({ zousan:require('./zousan').toString(), thenable:require('./thenableFactory').toString() }, function $asyncbind(self,catcher) { "use strict"; if (!Function.prototype.$asyncbind) { Object.defineProperty(Function.prototype,"$asyncbind",{value:$asyncbind,enumerable:false,configurable:true,writable:true}) ; } if (!$asyncbind.trampoline) { $asyncbind.trampoline = function trampoline(t,x,s,e,u){ return function b(q) { while (q) { if (q.then) { q = q.then(b, e) ; return u?undefined:q; } try { if (q.pop) { if (q.length) return q.pop() ? x.call(t) : q; q = s; } else q = q.call(t) } catch (r) { return e(r); } } } }; } if (!$asyncbind.LazyThenable) { $asyncbind.LazyThenable = '!!!thenable'(); $asyncbind.EagerThenable = $asyncbind.Thenable = ($asyncbind.EagerThenableFactory = '!!!zousan')(); } function boundThen() { return resolver.apply(self,arguments); } var resolver = this; switch (catcher) { case true: return new ($asyncbind.Thenable)(boundThen); case 0: return new ($asyncbind.LazyThenable)(boundThen); case undefined: /* For runtime compatibility with Nodent v2.x, provide a thenable */ boundThen.then = boundThen ; return boundThen ; default: return function(){ try { return resolver.apply(self,arguments); } catch(ex) { return catcher(ex); } } } }) ; function $asyncspawn(promiseProvider,self) { if (!Function.prototype.$asyncspawn) { Object.defineProperty(Function.prototype,"$asyncspawn",{value:$asyncspawn,enumerable:false,configurable:true,writable:true}) ; } if (!(this instanceof Function)) return ; var genF = this ; return new promiseProvider(function enough(resolve, reject) { var gen = genF.call(self, resolve, reject); function step(fn,arg) { var next; try { next = fn.call(gen,arg); if(next.done) { if (next.value !== resolve) { if (next.value && next.value===next.value.then) return next.value(resolve,reject) ; resolve && resolve(next.value); resolve = null ; } return; } if (next.value.then) { next.value.then(function(v) { step(gen.next,v); }, function(e) { step(gen.throw,e); }); } else { step(gen.next,next.value); } } catch(e) { reject && reject(e); reject = null ; return; } } step(gen.next); }); } // Initialize async bindings $asyncbind() ; $asyncspawn() ; // Export async bindings module.exports = { $asyncbind:$asyncbind, $asyncspawn:$asyncspawn };