diff --git a/examples/example.js b/examples/example.js index e9b9e77..613a087 100644 --- a/examples/example.js +++ b/examples/example.js @@ -6,7 +6,7 @@ let emitter = new EventEmitter() // let verbose = process.env.VERBOSE==='true' -let combo = false +let combo = true // handler: (r)=> console.log('result:',r) @@ -74,11 +74,19 @@ if (combo) { ) if (combo){ + console.log('a combination of e and pr was made\n','combinations are not added to \'all\' list') console.log('subscribing to sub combination e, pr') example.subscribe('combo',val => console.log('combo e, pr is:',val)) } } +let madeonly = example.makeObserver('madeonly') + +console.log('observer \'madeonly\' was only made and was not added so not in list \n',madeonly) +console.log('list of observers made and added to the all combination\n',example.observerNames) + + + emitter.emit('ec',{ready:true}) emitter.emit('pe','yup') emitter.emit('e') diff --git a/package.json b/package.json index 0dfea0a..f8f7bf3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@uci-utils/ready", - "version": "0.1.5", + "version": "0.1.6", "description": "A Class to Observe the reduced to boolean combined state of a map of observables", "main": "src/ready.js", "scripts": { diff --git a/src/ready.js b/src/ready.js index c9669af..2617e5a 100644 --- a/src/ready.js +++ b/src/ready.js @@ -10,7 +10,7 @@ import { createBoolean } from '@uci-utils/to-boolean' class Ready extends Map { constructor(opts) { super(opts.observables) - this.emitter = typeof opts.emitter.on ==='function' ? opts.emitter : null + this.emitter = isEmitter(opts.emitter) ? opts.emitter : null const toBool = createBoolean(opts.boolean) // e.g. {undefined:true} this.condition = opts.condition || ( (ev) => toBool(ev) ) this.subscriptions = new Map() @@ -70,17 +70,17 @@ class Ready extends Map { }) } - addObserver(name, obs, opts={} ) { + makeObserver(obs, opts={}) { + // validation and defaults, obs can be emitter, osbserver, or promise - if (!name || typeof(name)!=='string') return false // name required if (isPlainObject(obs)) { opts = obs; obs=null } if (!(obs || this.emitter)) return false // some observable requried - let { condition, event, details } = opts + let { condition, event, name} = opts condition = condition || this.condition - if (typeof (obs ||{}).on ==='function') obs = fromEvent(obs, event || name) // it's an emitter + if (isEmitter(obs) && (event || name)) obs = fromEvent(obs, event || name ) // it's an emitter if (isPromise(obs)) obs = from(obs) // it's a promise if (obs && !isObservable(obs) && typeof obs==='function' && arguments.length===2) condition = obs - if (!obs && this.emitter) obs = fromEvent(this.emitter,event || name) + if (!obs && this.emitter && (event || name)) obs = fromEvent(this.emitter,event || name) if (!obs || !isObservable(obs)) return false let xobs = obs.pipe( tap(val => this.log(`${name} emitted/resolved the value =>${JSON.stringify(val)}`)), @@ -88,17 +88,27 @@ class Ready extends Map { tap(val => this.log(`boolean: ${val}`)), startWith(false), shareReplay(1), - // multicast(new Subject()) ) - let sub = xobs.subscribe() - this.set(name, {obs:xobs, sub:sub}) - this.setObserverDetails(name,details) - this.combineObservers('__all__') // update total combo - if (this.subscriptions.has('__all__')) this.subscribe() // will resubscribe + xobs._readyType = true return xobs } - combineObservers(name,list) { + addObserver(name, obs, opts={} ) { + // validation and defaults, obs can be emitter, osbserver, or promise + if (!name || typeof(name)!=='string') return false // name required + opts.name = name + if (!(obs || {})._readyType) obs = this.makeObserver(obs, opts) + if (!isObservable(obs)) return false + let { details } = opts + let sub = obs.subscribe() + this.set(name, {obs:obs, sub:sub}) + this.setObserverDetails(name,details) + this.combineObservers('__all__',opts) // update total combo + if (this.subscriptions.has('__all__')) this.subscribe() // will resubscribe + return obs + } + // TODO add option for whether changed is enabled (default) or not and store with combo for remake + combineObservers(name,list,opts={}) { if (Array.isArray(name)) {list = name; name = null} name = name || '__all__' if (name==='__all__') list = Array.from(this.keys()) // get list of all observers @@ -136,7 +146,7 @@ class Ready extends Map { this.subscribe() // resubscribe to changed combo } - subscribe(name, handler) { + subscribe(name, handler, save) { // only one subscription at a time per observer or combination from this method if (typeof name ==='function') { handler=name @@ -148,7 +158,7 @@ class Ready extends Map { if (!obs) return false if (this.subscriptions.has(name)) this.subscriptions.get(name).subs.unsubscribe() let subs = obs.subscribe(handler) - this.subscriptions.set(name,{subs:subs,handler:handler}) + if (save) this.subscriptions.set(name,{subs:subs,handler:handler}) return subs } @@ -179,7 +189,14 @@ function map(fn) { return isAsync(fn) ? switchMap.call(this,fn) : simpleMap.call(this,fn) } +function isEmitter(emitter) { + if (!emitter) return false + let check = ['on','emit'] + return check.reduce((acc,fn)=> acc && typeof emitter[fn] ==='function',true) +} + function isAsync(fn) { + if (typeof fn !== 'function') return false return (isPromise(fn) || fn.constructor.name === 'AsyncFunction') }