0.1.10 add makeCombination, fix bug in makeObserver, refactor failed, add sending boolean event as array where first element is ready value to check
parent
333d565894
commit
205f9a2ccd
|
@ -2,3 +2,4 @@ tests/
|
||||||
test/
|
test/
|
||||||
*.test.js
|
*.test.js
|
||||||
testing/
|
testing/
|
||||||
|
examples/
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@uci-utils/ready",
|
"name": "@uci-utils/ready",
|
||||||
"version": "0.1.7",
|
"version": "0.1.10",
|
||||||
"description": "A Class to Observe the reduced to boolean combined state of a map of observables",
|
"description": "A Class to Observe the reduced to boolean combined state of a map of observables",
|
||||||
"main": "src/ready.js",
|
"main": "src/ready.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/uCOMmandIt/uci-utils#readme",
|
"homepage": "https://github.com/uCOMmandIt/uci-utils#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@uci-utils/to-boolean": "^0.1.1",
|
"@uci-utils/to-boolean": "^0.1.5",
|
||||||
"is-observable": "^2.0.0",
|
"is-observable": "^2.0.0",
|
||||||
"is-plain-object": "^3.0.0",
|
"is-plain-object": "^3.0.0",
|
||||||
"p-is-promise": "^3.0.0",
|
"p-is-promise": "^3.0.0",
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
"esm": "^3.2.25",
|
"esm": "^3.2.25",
|
||||||
"mocha": "^6.2.2",
|
"mocha": "^7.0.1",
|
||||||
"nodemon": "^1.19.4"
|
"nodemon": "^2.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
57
src/ready.js
57
src/ready.js
|
@ -8,12 +8,14 @@ import isPlainObject from 'is-plain-object'
|
||||||
import { createBoolean } from '@uci-utils/to-boolean'
|
import { createBoolean } from '@uci-utils/to-boolean'
|
||||||
|
|
||||||
class Ready extends Map {
|
class Ready extends Map {
|
||||||
constructor(opts) {
|
constructor(opts={}) {
|
||||||
super(opts.observables)
|
super(opts.observables)
|
||||||
this.emitter = isEmitter(opts.emitter) ? opts.emitter : null
|
this.emitter = isEmitter(opts.emitter) ? opts.emitter : null
|
||||||
const toBool = createBoolean(opts.boolean)
|
const toBool = createBoolean(opts.boolean)
|
||||||
this.toBoolean = (value) => {
|
this.toBoolean = (value) => {
|
||||||
|
// can emit plain object with ready prop, or array with first value as ready value or just ready value
|
||||||
if (isPlainObject(value)) value = (value.ready || value.online || value.active || false)
|
if (isPlainObject(value)) value = (value.ready || value.online || value.active || false)
|
||||||
|
if (Array.isArray(value)) value=value[0]
|
||||||
return toBool(value)
|
return toBool(value)
|
||||||
}
|
}
|
||||||
this.condition = opts.condition || ( (ev) => this.toBoolean(ev) )
|
this.condition = opts.condition || ( (ev) => this.toBoolean(ev) )
|
||||||
|
@ -27,19 +29,26 @@ class Ready extends Map {
|
||||||
if (opts.verbose||process.env.UCI_READY_VERBOSE==='true') this.logger.subscribe(console.log)
|
if (opts.verbose||process.env.UCI_READY_VERBOSE==='true') this.logger.subscribe(console.log)
|
||||||
this.handler = opts.handler || ((ready) => {console.log('default handler', ready)})
|
this.handler = opts.handler || ((ready) => {console.log('default handler', ready)})
|
||||||
this._first = true // tracks first emission
|
this._first = true // tracks first emission
|
||||||
|
console.log('@uci-utils/ready package tag 0.1.10')
|
||||||
}
|
}
|
||||||
|
|
||||||
get observers(){return Array.from(this.keys())}
|
get observers(){return Array.from(this.keys())}
|
||||||
get combinations(){return Array.from(this._combinations.keys())}
|
get combinations(){return Array.from(this._combinations.keys())}
|
||||||
get all() { return this._all}
|
get all() { return this._all}
|
||||||
|
|
||||||
get failure () {
|
get failed() {
|
||||||
let ret = null
|
// console.log('making failures from',this.state)
|
||||||
let failed = this.state.some(obs=> {
|
let failed = this.state
|
||||||
ret = obs[0]
|
.filter(([,ready]) => {
|
||||||
return obs[1]===false
|
// console.log('in filter', ready)
|
||||||
})
|
// return !await this.getValue(name)
|
||||||
return !failed ? '__none__' : ret
|
// ret = obs[0]
|
||||||
|
return !ready
|
||||||
|
})
|
||||||
|
.map(obs=> {return {name:obs[0], details: this.getObserverDetails(obs[0])} })
|
||||||
|
// console.log('failed as filtered', failed)
|
||||||
|
|
||||||
|
return failed.length ? failed : '__none__'
|
||||||
}
|
}
|
||||||
|
|
||||||
getObserverDetails(name) { return (this.get(name)||{}).details}
|
getObserverDetails(name) { return (this.get(name)||{}).details}
|
||||||
|
@ -67,9 +76,10 @@ class Ready extends Map {
|
||||||
getValue(name) { // NOT recommended. if there is any issue will return false
|
getValue(name) { // NOT recommended. if there is any issue will return false
|
||||||
let obs = this.getObserver(name)
|
let obs = this.getObserver(name)
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
setTimeout(()=>resolve(false),50)
|
setTimeout(()=>resolve(false),100)
|
||||||
if (isObservable(obs)){
|
if (isObservable(obs)){
|
||||||
const sub = obs.subscribe(val => {
|
const sub = obs.subscribe(val => {
|
||||||
|
console.log('in value subscriber', name,val)
|
||||||
resolve(val)
|
resolve(val)
|
||||||
})
|
})
|
||||||
sub.unsubscribe()
|
sub.unsubscribe()
|
||||||
|
@ -85,13 +95,18 @@ class Ready extends Map {
|
||||||
condition = condition || this.condition
|
condition = condition || this.condition
|
||||||
if (isEmitter(obs) && (event || name)) 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 (isPromise(obs)) obs = from(obs) // it's a promise
|
||||||
if (!obs && this.emitter && (event || name)) obs = fromEvent(this.emitter,(event || name))
|
if ((!obs || typeof obs==='string') && this.emitter && (event || name || obs)) obs = fromEvent(this.emitter,(event || name || obs))
|
||||||
if (!obs || !isObservable(obs)) return false
|
if (!obs || !isObservable(obs)) return false
|
||||||
let xobs = obs.pipe(
|
let xobs = obs.pipe(
|
||||||
tap(val => this.log(`${name} emitted/resolved the value =>${JSON.stringify(val)}`)),
|
tap(val => this.log(`${name} emitted/resolved the value =>${JSON.stringify(val)}`)),
|
||||||
|
// tap(val => console.log(`${name} emitted/resolved the value =>${JSON.stringify(val)}`)),
|
||||||
// TODO retain plain object if it has a ready property
|
// TODO retain plain object if it has a ready property
|
||||||
map(condition),
|
map(condition),
|
||||||
|
// tap(val => console.log(`boolean: ${val}`)),
|
||||||
tap(val => this.log(`boolean: ${val}`)),
|
tap(val => this.log(`boolean: ${val}`)),
|
||||||
|
map(val => {
|
||||||
|
// if (opts.reverse) console.log('reversing', val, opts.reverse ? !val : val)
|
||||||
|
return opts.reverse ? !val : val}),
|
||||||
startWith(false),
|
startWith(false),
|
||||||
// shareReplay({refCount:true, bufferSize:1}),
|
// shareReplay({refCount:true, bufferSize:1}),
|
||||||
shareReplay(1),
|
shareReplay(1),
|
||||||
|
@ -131,6 +146,19 @@ class Ready extends Map {
|
||||||
// TODO update affected combinations
|
// TODO update affected combinations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO have combineObservers call this
|
||||||
|
makeCombination(observers,list){
|
||||||
|
observers = observers.filter(obs=>obs._readyType)
|
||||||
|
if (!observers.length) return false
|
||||||
|
let combination = combineLatest(observers).pipe(
|
||||||
|
tap(states => { if (list) this.log(list.map((name,index) => [name,states[index]]))}),
|
||||||
|
map(states => states.reduce((res,state) => {return res && state},true)),
|
||||||
|
changed(), //filters out emission if it is unchanged from last TODO replace with distinctUntilChanged
|
||||||
|
shareReplay(1)
|
||||||
|
)
|
||||||
|
return combination
|
||||||
|
}
|
||||||
|
|
||||||
// TODO add option for whether changed is enabled (default) or not and store with combo for remake
|
// TODO add option for whether changed is enabled (default) or not and store with combo for remake
|
||||||
combineObservers(name,list,opts={}) {
|
combineObservers(name,list,opts={}) {
|
||||||
if (!name || typeof(name)!=='string') return false // name required
|
if (!name || typeof(name)!=='string') return false // name required
|
||||||
|
@ -141,14 +169,7 @@ class Ready extends Map {
|
||||||
else return false
|
else return false
|
||||||
}
|
}
|
||||||
let observers = list.map(name=>{return name._readyType ? name : this.getObserver(name)})
|
let observers = list.map(name=>{return name._readyType ? name : this.getObserver(name)})
|
||||||
observers = observers.filter(obs=>obs._readyType)
|
const combination = this.makeCombination(observers,list)
|
||||||
if (!observers.length) return false
|
|
||||||
let combination = combineLatest(observers).pipe(
|
|
||||||
tap(states => { this.log(list.map((name,index) => [name,states[index]]))}),
|
|
||||||
map(states => states.reduce((res,state) => {return res && state},true)),
|
|
||||||
changed(), //filters out emission if it is unchanged from last
|
|
||||||
shareReplay(1)
|
|
||||||
)
|
|
||||||
this._combinations.set(name, combination) // if name passed then save combo in Map
|
this._combinations.set(name, combination) // if name passed then save combo in Map
|
||||||
return combination
|
return combination
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue