better isRx will determine if any parent to root is reactive

master
Kebler Network System Administrator 2021-05-13 11:53:48 -07:00
parent 543cad8bac
commit 4b76b80f07
1 changed files with 89 additions and 39 deletions

View File

@ -1,3 +1,4 @@
// import methods from './public-methods.js'
// native modules // native modules
import { EventEmitter } from 'events' import { EventEmitter } from 'events'
// reactive modules // reactive modules
@ -5,7 +6,7 @@ import { BehaviorSubject, from } from 'rxjs'
import { distinctUntilChanged, skip } from 'rxjs/operators' import { distinctUntilChanged, skip } from 'rxjs/operators'
// uci modules // uci modules
import { check } from '@uci-utils/type' import { check } from '@uci-utils/type'
import { get, set, del, getKeys, pathToString } from '@uci-utils/obj-nested-prop' import { get, set, del, walkPath, getKeys, pathToString } from '@uci-utils/obj-nested-prop'
import { logger } from '@uci-utils/logger' import { logger } from '@uci-utils/logger'
// supporting // supporting
import equal from 'deep-equal' import equal from 'deep-equal'
@ -17,7 +18,6 @@ const log = logger({ file: '/src/rx-class.js', package: '@uci-utils/rx-class', c
class RxClass extends EventEmitter { class RxClass extends EventEmitter {
// private fields // private fields
#rx #rx
#rxM
constructor (opts = {}) { constructor (opts = {}) {
super(opts) super(opts)
@ -32,8 +32,9 @@ class RxClass extends EventEmitter {
hook: rxopts.hook, // function called when setting hook: rxopts.hook, // function called when setting
namespace: rxopts.namespace || 'rx', // TODO namespace to added to all public rx methods namespace: rxopts.namespace || 'rx', // TODO namespace to added to all public rx methods
operators: new Map(), // TODO added to all rx pipes, in order operators: new Map(), // TODO added to all rx pipes, in order
skip: rxopts.skip == null ? 0 : rxopts.skip skip: rxopts.skip == null ? 1 : rxopts.skip
} }
this.isRx.bind(this)
} }
get (path) { get (path) {
@ -51,25 +52,29 @@ class RxClass extends EventEmitter {
} }
set (path, value, opts = {}) { set (path, value, opts = {}) {
// console.log(path,value,opts,!this.isRx(path)) console.log('set:', path, value, opts, !this.isRx(path))
if (!opts.noRx && !this.isRx(path)) { if (!opts.noRx && !this.isRx(path)) { // travsere
opts = Object.assign(check.isPlainObject(value) ? { values: value, traverse: true } : { value: value }, opts) opts = Object.assign(
// console.log('set opts', opts) (check.isPlainObject(value) && opts.traverse !== false)
? { values: value, traverse: true }
: { value: value }
, opts)
console.log('adding rx from set', opts)
this.rxAdd(path, opts) this.rxAdd(path, opts)
} else { } else {
const curValue = this.#get(path) const curValue = this.#get(path)
if (!equal(curValue, value) && value !== undefined) { if (!equal(curValue, value) && value !== undefined) {
// console.log('in set', path,value) console.log('setting already reactive value', path, value)
this.#set(path, value) this.#set(path, value)
// console.log('value that was set',this.#get(path)) console.log('value that was set', this.#get(path))
} }
return this.#get(path) return this.#get(path)
} }
} }
// getRaw () { getRaw () {
// return get(this, [this.#rx.namespace, ...arguments]) return get(this, [this.#rx.namespace, ...arguments])
// } }
// if property exists it moves value to #rx.props and creates getter and setter and behavior subject // if property exists it moves value to #rx.props and creates getter and setter and behavior subject
rxAdd (path, opts = {}) { rxAdd (path, opts = {}) {
@ -78,23 +83,24 @@ class RxClass extends EventEmitter {
const self = this const self = this
// console.log('object to traverse', obj) // console.log('object to traverse', obj)
traverse(obj).map(function () { traverse(obj).map(function () {
// console.log('traversing', this)
if (this.isLeaf) { if (this.isLeaf) {
const lpath = this.path const lpath = this.path
lpath.unshift(path) lpath.unshift(path)
// console.log(`#{!opts.values ? 'existing':'new'} leaf on path '#{lpath}' with value: #{this.node}`) // console.log('#{!opts.values ? \'existing\':\'new\'} leaf on path \'#{lpath}\' with value: #{this.node}')
self.rxAdd(lpath, { value: this.node }) self.rxAdd(lpath, { value: this.node })
} }
return true
} }
) )
return true return true
} // end traverse } // end traverse
if (this.isRx(path) && !opts.force) return true
const value = this.#get(path) // current value const value = this.#get(path) // current value
if (value === undefined) { if (value === undefined) {
// console.log('no current property or value for', path, 'creating temporary null') // console.log('no current property or value for', path, 'creating temporary null')
this.#set(path, null) this.#set(path, null)
} }
if (this.isRx(path) && !opts.force) return true
console.log(path, 'making reactive')
const { parent, name } = this.#rxGetObj(path, '__parent__') const { parent, name } = this.#rxGetObj(path, '__parent__')
log.debug({ log.debug({
class: 'RxClass', class: 'RxClass',
@ -149,6 +155,7 @@ class RxClass extends EventEmitter {
if (check.isFunction(rx.hook)) rx.hook.call(self, value) // property hook if (check.isFunction(rx.hook)) rx.hook.call(self, value) // property hook
} }
}) })
// console.log('rxadd done', path, opts, this.#get(['#rx.props', path]))
return true return true
} }
@ -183,7 +190,6 @@ class RxClass extends EventEmitter {
lpath.unshift(path) lpath.unshift(path)
if (self.isRx(lpath)) self.rxRemove(lpath, { confirm: true }) if (self.isRx(lpath)) self.rxRemove(lpath, { confirm: true })
} }
return true
}) })
// all done removing the leaves so remove branch // all done removing the leaves so remove branch
this.#del(['#rx.props', path], true) this.#del(['#rx.props', path], true)
@ -244,29 +250,73 @@ class RxClass extends EventEmitter {
return false return false
} }
// // takes several formats for a path to an objects property and return only the . string isGetSet (path) {
// formatObjPath (path) { const keys = getKeys(path)
// if (path == null) return path const prop = keys.pop()
// if (Array.isArray(path)) { const parent = this.#get(keys)
// path = path.filter(Boolean).join('.') // Boolean filter strips empty strings or null/undefined // console.log('isgetset', path, keys, prop, 'parent?', !!parent)
// } if (parent && prop) {
// path = path.replace(/\/:,/g, '.') // replaces /:, with . return !!(Object.getOwnPropertyDescriptor(parent, prop) || {}).get &&
// return path !!(Object.getOwnPropertyDescriptor(parent, prop) || {}).set
// }
// checks for getter and the corresponding rx object
isRx (path) {
// console.log(path)
if (this.#get(path) === undefined) return false
const { parent, name, parentPath } = this.#rxGetObj(path, '__parent__')
// console.log(parent, name, parentPath)
const rxparent = this.#get(['#rx.props', parentPath]) || {}
const rx = rxparent[name]
// console.log(path, 'rxparent,rx', !!parent, !!name, !!rxparent, !!rx)
if (!rx) return false
// console.log(Object.getOwnPropertyDescriptor(parent, name).get)
return !!Object.getOwnPropertyDescriptor(parent, name).get
} }
return false
}
// is already reactive, checks for setter/getter and the corresponding rx object
isRx (path) {
// console.log('in isRX', path)
const keys = getKeys(path)
const cnt = keys.length
for (let index = 0; index < cnt; index++) {
// console.log('testing rx', index, cnt, keys, !!this.#get(keys), !!this.isGetSet(keys), !!this.#get(['#rx.props', keys]))
if (this.#get(keys) === undefined) return false
if (this.isGetSet(keys) && this.#get(['#rx.props', keys])) return true
keys.pop()
}
return false
// // console.log('in rx every', lpath)
// // if (this.#get(['#rx.props', ...lpath]) === undefined) {
// // return false
// // }
// //
// console.log(parent, name, parentPath)
// const rxparent = this.#get(['#rx.props', parentPath]) || {}
// const rx = rxparent[name]
// console.log(path, 'rxparent,rx', !!parent, !!name, !!rxparent, !!rx)
// if (!rx) return true
// else {
// console.log(Object.getOwnPropertyDescriptor(parent, name).get)
// isRx = !!Object.getOwnPropertyDescriptor(parent, name).get
// return false
// }
// })
// return isRx
}
// isRx(path) {
// // console.log(path)
// let isRx = false
// const lpath = []
// getKeys(path).every(key => {
// lpath.push(key)
// console.log('in rx every', lpath, this.#get(lpath))
// if (this.#get(lpath) === undefined) {
// return false
// }
// // const { parent, name, parentPath } = this.#rxGetObj(lpath, '__parent__')
// // console.log(parent, name, parentPath)
// const rxparent = this.#get(['#rx.props', parentPath]) || {}
// const rx = rxparent[name]
// console.log(path, 'rxparent,rx', !!parent, !!name, !!rxparent, !!rx)
// if (!rx) return true
// else {
// console.log(Object.getOwnPropertyDescriptor(parent, name).get)
// isRx = !!Object.getOwnPropertyDescriptor(parent, name).get
// return false
// }
// })
// return isRx
// }
// PRIVATE METHODS // PRIVATE METHODS