finished move to .walk2(..)

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2019-05-11 03:02:42 +03:00
parent 03685c643c
commit e7ba8fa505

View File

@ -583,6 +583,7 @@ var BaseBrowserPrototype = {
// XXX can this support breadth first walking??? // XXX can this support breadth first walking???
// XXX revise protocol... // XXX revise protocol...
// XXX use generic-walk.... (???) // XXX use generic-walk.... (???)
/*
walk: function(func, options){ walk: function(func, options){
var that = this var that = this
@ -616,11 +617,6 @@ var BaseBrowserPrototype = {
{root: this}) {root: this})
: options : options
/*var start = options.start || 0
var end = options.end
|| (options.count >= 0 && start + (options.count))
|| Infinity
//*/
var iterateNonIterable = options.iterateAll || options.iterateNonIterable var iterateNonIterable = options.iterateAll || options.iterateNonIterable
var iterateCollapsed = options.iterateAll || options.iterateCollapsed var iterateCollapsed = options.iterateAll || options.iterateCollapsed
var skipNested = !options.iterateAll && options.skipNested var skipNested = !options.iterateAll && options.skipNested
@ -763,27 +759,28 @@ var BaseBrowserPrototype = {
res.flat() res.flat()
: res : res
}, },
//*/
// //
// Get list of nodes in tree... // Get list of nodes in tree...
// .walk2() // .walk()
// -> list // -> list
// //
// Walk the tree passing each node to func(..) // Walk the tree passing each node to func(..)
// .walk2(func(..)[, options]) // .walk(func(..)[, options])
// -> list // -> list
// //
// Walk tree passing each node to func(..) using method name to // Walk tree passing each node to func(..) using method name to
// walk nested browsers... // walk nested browsers...
// NOTE: 'walk2' is used as name if name is not present in the object... // NOTE: 'walk' is used as name if name is not present in the object...
// .walk2(func(..), name, args(..)[, options]) // .walk(func(..), name, args(..)[, options])
// .walk2(func(..), name, args(..), walkable(..)[, options]) // .walk(func(..), name, args(..), walkable(..)[, options])
// -> list // -> list
// //
// Walk tree passign each node to func(..) and handle nested browser // Walk tree passign each node to func(..) and handle nested browser
// walking in recursion(..) optionally testing if walkable with walkable(..) // walking in recursion(..) optionally testing if walkable with walkable(..)
// .walk2(func(..), recursion(..)[, options]) // .walk(func(..), recursion(..)[, options])
// -> list // -> list
// //
// //
@ -814,9 +811,9 @@ var BaseBrowserPrototype = {
// For examples see: .text(..), .paths(..) and .map(..) // For examples see: .text(..), .paths(..) and .map(..)
// //
// //
// NOTE: if recursion(..) is not given then .walk2(..) is used to // NOTE: if recursion(..) is not given then .walk(..) is used to
// handle nested children... // handle nested children...
// NOTE: if walkable(..) is not given then we check for .walk2(..) // NOTE: if walkable(..) is not given then we check for .walk(..)
// availability... // availability...
// NOTE: children arrays are handled internally... // NOTE: children arrays are handled internally...
// //
@ -829,16 +826,16 @@ var BaseBrowserPrototype = {
// + this is done so as to provide the user a simpler // + this is done so as to provide the user a simpler
// .map(..)-like form... // .map(..)-like form...
// Ex: // Ex:
// .walk2((e, i, p, next, stop) => p.join('/')) // .walk((e, i, p, next, stop) => p.join('/'))
// // vs. // // vs.
// .walk2((e, c, next, stop) => c.path.join('/')) // .walk((e, c, next, stop) => c.path.join('/'))
// - two ways to get index and one to update it... // - two ways to get index and one to update it...
// ...if this can produce errors we need to simplify... // ...if this can produce errors we need to simplify...
// XXX add docs: // XXX add docs:
// - maintaining context to implement/extend walkers... // - maintaining context to implement/extend walkers...
// - correctly stopping recursive calls (call root stop(..)) // - correctly stopping recursive calls (call root stop(..))
// XXX can this be simpler??? // XXX can this be simpler???
walk2: function(func, recursion, walkable, options){ walk: function(func, recursion, walkable, options){
var that = this var that = this
// parse args... // parse args...
@ -858,7 +855,7 @@ var BaseBrowserPrototype = {
: null : null
// sanity check... // sanity check...
if(formArgs == null && typeof(recursion) == typeof('str')){ if(formArgs == null && typeof(recursion) == typeof('str')){
throw new Error(`.walk2(func, name, formArgs, ..): ` throw new Error(`.walk(func, name, formArgs, ..): `
+`expected function as third argument, got: ${formArgs}.`) } +`expected function as third argument, got: ${formArgs}.`) }
var walkable = (!formArgs var walkable = (!formArgs
&& (args[0] instanceof Function && (args[0] instanceof Function
@ -893,7 +890,7 @@ var BaseBrowserPrototype = {
// requested method name is available... // requested method name is available...
|| (typeof(recursion) == typeof('str') || (typeof(recursion) == typeof('str')
&& node[recursion]) && node[recursion])
|| node.walk2 ) } || node.walk ) }
return walk( return walk(
function(state, node, next, stop){ function(state, node, next, stop){
@ -910,6 +907,9 @@ var BaseBrowserPrototype = {
if(nested !== false){ if(nested !== false){
return nested } return nested }
if(children == null){
return [] }
// normalize... // normalize...
list = list === true ? list = list === true ?
children children
@ -919,9 +919,9 @@ var BaseBrowserPrototype = {
children children
: list : list
// call .walk2(..) recursively... // call .walk(..) recursively...
var useWalk = function(){ var useWalk = function(){
return list.walk2( return list.walk(
func, func,
recursion, recursion,
...(formArgs instanceof Function ? ...(formArgs instanceof Function ?
@ -935,7 +935,7 @@ var BaseBrowserPrototype = {
// handle arrays internally... // handle arrays internally...
: list instanceof Array ? : list instanceof Array ?
// NOTE: this gets the path and i from context... // NOTE: this gets the path and i from context...
next('do', state, next('do', [],
...(reverse ? ...(reverse ?
list.slice().reverse() list.slice().reverse()
: list)) : list))
@ -953,18 +953,13 @@ var BaseBrowserPrototype = {
list, context.index, p, list, context.index, p,
options, context, options, context,
func, useWalk) || [])) func, useWalk) || []))
// .walk2(..) // .walk(..)
: useWalk()) : useWalk())
// normalize and merge to state... // normalize and merge to state...
.run(function(){ .run(function(){
nested = this instanceof Array ? return (nested = this instanceof Array ?
this this
: [this] : [this]) }) }
// merge...
!(list === false || list instanceof Array)
&& state.splice(state.length, 0, ...nested)
return nested
}) }
// prepare context... // prepare context...
var id = node.id || node.value var id = node.id || node.value
@ -990,7 +985,7 @@ var BaseBrowserPrototype = {
// reverse -> do children... // reverse -> do children...
reverse == 'flat' reverse == 'flat'
&& children && children
&& doNested() && state.splice(state.length, 0, ...doNested())
// do element... // do element...
state.splice(state.length, 0, state.splice(state.length, 0,
// NOTE: here we use: // NOTE: here we use:
@ -1007,6 +1002,9 @@ var BaseBrowserPrototype = {
[null, context.index] [null, context.index]
: [node, context.index++]), : [node, context.index++]),
p, p,
// NOTE: when calling this it is the
// responsibility of the caller to return
// the result to be added to state...
doNested, doNested,
stop, stop,
children) || []) children) || [])
@ -1016,9 +1014,12 @@ var BaseBrowserPrototype = {
// the call will have no effect, but we need to // the call will have no effect, but we need to
// update the context... // update the context...
children children
&& (doNested(), && nested === false
// restore path context... && state.splice(state.length, 0, ...doNested())
context.path.pop())
// restore path context...
children
&& context.path.pop()
return state return state
}, },
@ -1038,7 +1039,7 @@ var BaseBrowserPrototype = {
// XXX rename this?? // XXX rename this??
text: function(options, context){ text: function(options, context){
return this return this
.walk2( .walk(
function(node, i, path){ function(node, i, path){
return node ? return node ?
path.slice(1) path.slice(1)
@ -1051,7 +1052,7 @@ var BaseBrowserPrototype = {
options, context) options, context)
.join('\n') }, .join('\n') },
paths: function(options, context){ paths: function(options, context){
return this.walk2( return this.walk(
function(n, i, p){ function(n, i, p){
return n return n
&& [(options || {}).joinPaths !== false ? && [(options || {}).joinPaths !== false ?
@ -1061,10 +1062,28 @@ var BaseBrowserPrototype = {
function(_, i, path, options, context){ function(_, i, path, options, context){
// NOTE: for paths and indexes to be consistent between // NOTE: for paths and indexes to be consistent between
// levels we need to thread the context on, here and // levels we need to thread the context on, here and
// into the base .walk2(..) call below... // into the base .walk(..) call below...
return [options, context] }, return [options, context] },
options, context) }, options, context) },
// XXX test manual recursion...
text2: function(options, context){
return this
.walk(
function(node, i, path, next){
return node == null ?
[]
: [path.slice(1)
.map(e => ' ')
.join('') + (node.value || node)]
.concat(node.children ?
next()
: []) },
'text2',
function(func, i, path, options, context){
return [options, context] },
options, context)
.join('\n') },
// Extended map... // Extended map...
// //
@ -1123,7 +1142,7 @@ var BaseBrowserPrototype = {
: options : options
var context = args.shift() var context = args.shift()
return this.walk2( return this.walk(
function(elem, i, path){ function(elem, i, path){
return elem != null ? return elem != null ?
[func === undefined ? [func === undefined ?
@ -1351,7 +1370,7 @@ var BaseBrowserPrototype = {
return res return res
|| get.call(this.__search_test_generators__, pattern) }, false) ) || get.call(this.__search_test_generators__, pattern) }, false) )
return this.walk2( return this.walk(
function(elem, i, path, next, stop){ function(elem, i, path, next, stop){
// match... // match...
var res = (elem var res = (elem
@ -1489,7 +1508,7 @@ var BaseBrowserPrototype = {
this.map(...arguments) this.map(...arguments)
return this }, return this },
filter: function(func, options, context){ filter: function(func, options, context){
return this.walk2( return this.walk(
function(e, i, p){ function(e, i, p){
return e && func.call(this, e, i, p) ? [e] : [] }, return e && func.call(this, e, i, p) ? [e] : [] },
'filter', 'filter',
@ -1499,7 +1518,7 @@ var BaseBrowserPrototype = {
reduce: function(func, start, options){ reduce: function(func, start, options){
var that = this var that = this
var context = arguments[3] || {result: start} var context = arguments[3] || {result: start}
this.walk2( this.walk(
function(e, i, p){ function(e, i, p){
context.result = e ? context.result = e ?
func.call(that, context.result, e, i, p) func.call(that, context.result, e, i, p)
@ -1529,8 +1548,9 @@ var BaseBrowserPrototype = {
pathOf: function(item, options){ pathOf: function(item, options){
return this.positionOf(item, options)[1] }, return this.positionOf(item, options)[1] },
// Like .get(.., {iterateCollapsed: true}) but will expand all the // Like .select(.., {iterateCollapsed: true}) but will expand all the
// path items to reveal the target... // path items to reveal the target...
//
// XXX should this return the item or this??? // XXX should this return the item or this???
// XXX make .reveal('all'/'*') only do the actual nodes that need expanding... // XXX make .reveal('all'/'*') only do the actual nodes that need expanding...
// ...currently for path 'a/b/c/d' we'll go through: // ...currently for path 'a/b/c/d' we'll go through:
@ -1827,75 +1847,45 @@ var BaseBrowserPrototype = {
// the state anew that use .update(..)... // the state anew that use .update(..)...
// NOTE: currently options and context are distinguished only via // NOTE: currently options and context are distinguished only via
// the .options attribute... // the .options attribute...
// render: function(options, renderer, context){
// XXX would be nice to add ability to do a full render but not context = context || {}
// finalize the result...
// XXX BUG: calling .render() removes all non-iterable items for some reason...
render: function(options, renderer){
var that = this
// XXX Q: should options and context be distinguished only via
// the .options attr as is the case now???
// ...see no reason why not, though it does not feel right...
var context = (options == null || options.options == null) ?
{
root: this,
// NOTE: we are not combining this with .options as nested
// lists can have their own unique sets of options
// independently of the root list...
//options: options || this.options || {},
options: Object.assign(
Object.create(this.options || {}),
// defaults...
// XXX is this the correct way to setup defaults???
{ iterateNonIterable: true },
options || {}),
}
: options
options = context.options
renderer = renderer || this renderer = renderer || this
options = context.options
|| Object.assign(
Object.create(this.options || {}),
{ iterateNonIterable: true },
options || {})
context.options = context.options || options
// XXX should we control render parameters (range, start, end, ...) var elems = this.walk(
// from outside render and pass this info down to nested lists??? function(elem, i, path, nested, stop, children){
// ...if yes how?? return (
// - options // inline...
// - arg threading elem == null ?
var items = this // NOTE: here we are forcing rendering of the
.walk( // inline browser/list, i.e. ignoring
function(i, path, item, nested, children){ // options.skipNested for inline stuff...
return ( [ renderer.renderGroup(nested(true), context) ]
// inline... // nested...
(item == null && children) ? : elem.children ?
// NOTE: here we are forcing rendering of the [ renderer.renderNested(
// inline browser/list, i.e. ignoring renderer.renderNestedHeader(elem, i, context),
// options.skipNested for inline stuff... nested(),
// NOTE: we here do not distinguish between elem,
// inlined lists and browsers... (XXX ???) context) ]
[ renderer.renderGroup(nested(true), context) ] // normal elem...
// nested... : [ renderer.renderItem(elem, i, context) ] ) },
: children ? 'render',
[ renderer.renderNested( function(_, i, p, options, context){
renderer.renderNestedHeader(item, i, context), return [options, renderer, context] },
nested(), options, context)
item,
context) ]
// normal item...
: [ renderer.renderItem(item, i, context) ] ) },
function(func, i, path, children, options){
return children.render(context, renderer, i, path) },
// make the element render less strict...
function(elem){
return elem
&& elem.render instanceof Function },
// pass on i and path if given...
...[...arguments].slice(2),
options)
// determine the render mode... // determine the render mode...
return (!options.nonFinalized && context.root === this) ? return (!options.nonFinalized && context.root === this) ?
// root context -> render list and return this... // root context -> render list and return this...
renderer.renderFinalize(items, context) renderer.renderFinalize(elems, context)
// nested context -> return item list... // nested context -> return item list...
: items : elems
}, },