added path searching...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2018-12-13 18:36:58 +03:00
parent f237adc073
commit 3d5f428ce8

View File

@ -274,18 +274,18 @@ var TagsPrototype = {
return this.constructor.parseQuery.call(this, query) }, return this.constructor.parseQuery.call(this, query) },
// Match tags... // Match tags directly...
// //
// Check if tags match... // Check if tags match...
// .match(tag, tag) // .directMatch(tag, tag)
// -> bool // -> bool
// //
// Get all matching tags... // Get all matching tags...
// .match(tag) // .directMatch(tag)
// -> tags // -> tags
// //
// Filter out non-matching from tags... // Filter out non-matching from tags...
// .match(tag, tags) // .directMatch(tag, tags)
// -> tags // -> tags
// //
// //
@ -339,9 +339,9 @@ var TagsPrototype = {
// //
// //
// NOTE: this is not symmetric e.g. a will match a:b but not vice-versa. // NOTE: this is not symmetric e.g. a will match a:b but not vice-versa.
// // NOTE: this does not try to match outside the scope of the actual
// XXX BUG: /aaa matching... // given tags, to search taking paths into account use .match(..)
match: function(a, b, cmp){ directMatch: function(a, b, cmp){
var that = this var that = this
if(b instanceof Function){ if(b instanceof Function){
@ -353,7 +353,7 @@ var TagsPrototype = {
if(b == null || b instanceof Array){ if(b == null || b instanceof Array){
return (b || this.tags()) return (b || this.tags())
.filter(function(tag){ .filter(function(tag){
return that.match(a, tag)}) return that.directMatch(a, tag, cmp)})
// match two tags... // match two tags...
} else { } else {
@ -389,20 +389,88 @@ var TagsPrototype = {
// //
// NOTE: we do not need to use cmp(..) here as we are testing // NOTE: we do not need to use cmp(..) here as we are testing
// tag compatibility deeper in matchSet(..)... // tag compatibility deeper in matchSet(..)...
a = a.split(/[\/\\]/g) var sa = a.split(/[\/\\]/g)
b = b.split(/[\/\\]/g) var sb = b.split(/[\/\\]/g)
return b return sb
.reduce(function(a, e){ .reduce(function(a, e){
return (a[0] return (a[0]
&& (a[0] == '*' && (a[0] == '*'
|| matchSet(a[0], e))) ? || matchSet(a[0], e))) ?
a.slice(1) a.slice(1)
: a : a
}, a) }, sa)
.length == 0 .length == 0
} }
}, },
// Match tags directly or indirectly...
//
// This is the same as .directMatch(..) but also uses paths to check
// tag "reachability"...
//
// Matching rule:
// a and b match iff both a and b are reachable on a single path
// where a is above b.
//
//
// Example:
// ts.togglePersistent('a/b/c', 'a/x/y', 'c/d/e')
//
// // see if 'a' directly matches 'c'...
// ts.directMatch('a', 'c') // -> false
//
// // indirect matches...
// ts.match('a', 'c') // -> true
// ts.match('a', 'y') // -> true
// // indirect extended match...
// ts.match('a', 'e') // -> true
//
// // two different paths...
// ts.match('c', 'y') // -> false
// // path search is directional...
// ts.match('c', 'a') // -> false
//
//
match: function(a, b, cmp){
var that = this
var res = this.directMatch(...arguments)
// get paths with tag...
var paths = function(tag){
return that.directMatch(tag, cmp)
.filter(function(t){
return /[\\\/]/.test(t) }) }
// search the path tree...
// NOTE: this will stop the search on first hit...
var search = function(tag, seen){
seen = seen || new Set()
return paths(tag)
.reduce(function(res, path){
if(res == true){
return res
}
path = path.split(/[\\\/]/g)
// restrict direction...
path = path.slice(0, path.indexOf(tag))
// check current set of reachable tags...
return (that.directMatch(a, path, cmp).length != 0)
|| path
// search next level...
.reduce(function(res, tag){
return res ?
res
: seen.has(tag) ?
false
: search(tag, seen.add(tag)) }, false) }, false) }
return res === false ?
search(b)
: res
},
// Search tags... // Search tags...
// //
// Search the tags... // Search the tags...
@ -446,6 +514,7 @@ var TagsPrototype = {
// (i.e. ['a:b:c', 'a:b', 'a:c', 'a']) and will only return // (i.e. ['a:b:c', 'a:b', 'a:c', 'a']) and will only return
// the actual full match and an individual tag match... // the actual full match and an individual tag match...
// XXX should it??? // XXX should it???
// XXX should this search up the path???
search: function(query, tags){ search: function(query, tags){
var that = this var that = this
tags = tags == null ? tags = tags == null ?
@ -468,6 +537,8 @@ var TagsPrototype = {
.concat(that.subTags(this)) .concat(that.subTags(this))
.unique() }) .unique() })
.filter(function(t){ .filter(function(t){
// XXX should this search up the path???
//return that.directMatch(query, t, cmp) }) },
return that.match(query, t, cmp) }) }, return that.match(query, t, cmp) }) },
@ -556,6 +627,16 @@ var TagsPrototype = {
// XXX should we combine this with .tags(..) ??? // XXX should we combine this with .tags(..) ???
singleTags: function(value, ...tags){ singleTags: function(value, ...tags){
return this.subTags(this.tags(...arguments)).unique() }, return this.subTags(this.tags(...arguments)).unique() },
// XXX should this support ...tags???
// XXX should this expand paths???
// ...i.e. show all the paths a value participates in...
paths: function(value){
return this.tags(value)
.filter(function(tag){ return /[\\\/]/.test(tag) }) },
// XXX should this support ...tags???
sets: function(){
return this.tags(value)
.filter(function(tag){ return tag.includes(':') }) },
// //
// Get all values... // Get all values...
// .values() // .values()
@ -641,7 +722,7 @@ var TagsPrototype = {
} }
return this return this
}, },
// XXX save un-normalized tags as aliases... // XXX save un-normalized tags as aliases... ???
// XXX when value is not given, add tags to persistent tags... // XXX when value is not given, add tags to persistent tags...
tag: function(tags, value){ tag: function(tags, value){
var that = this var that = this
@ -812,6 +893,7 @@ var TagsPrototype = {
: 'off') }) : 'off') })
}, },
// Rename a tag...
// //
// Rename tag... // Rename tag...
// .rename(from, to) // .rename(from, to)