mixed a stupid bug... (RegExp state)

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2018-12-21 18:30:08 +03:00
parent adee84763e
commit 8f4c03cfdd
2 changed files with 83 additions and 30 deletions

View File

@ -271,8 +271,8 @@ module.TagsEdit = core.ImageGridFeatures.Feature({
// cleanup... // cleanup...
if(res.index.data && res.index.data.tags){ if(res.index.data && res.index.data.tags){
delete res.index.data.tags.tags.marked delete (res.index.data.tags.__index || {}).marked
delete res.index.data.tags.tags.bookmark delete (res.index.data.tags.__index || {}).bookmark
delete res.index.data.tags delete res.index.data.tags
} }
}], }],

View File

@ -27,7 +27,7 @@
* *
* XXX should we do .optimizeTags(tag) on .tag(tag)??? * XXX should we do .optimizeTags(tag) on .tag(tag)???
* ...this might lead to non-trivial behaviour... * ...this might lead to non-trivial behaviour...
* XXX should this serialize recursively down??? * XXX should this serialize recursively down (i.e. serialize items)???
* ...it might be a good idea to decide on a serialization * ...it might be a good idea to decide on a serialization
* protocol and use it throughout... * protocol and use it throughout...
* XXX should .tags() return all the used tags + .persistent or * XXX should .tags() return all the used tags + .persistent or
@ -291,7 +291,8 @@ var BaseTagsPrototype = {
// } // }
// //
// NOTE: a definition is equivalent to a very specific path tag but // NOTE: a definition is equivalent to a very specific path tag but
// considering it's a special case it is handled allot faster... // considering it's a strict special case it is optimised and
// handled allot faster...
// .define('birds', 'bird:many') // .define('birds', 'bird:many')
// is equivalent to: // is equivalent to:
// .togglePersistent('bird:many/birds') // .togglePersistent('bird:many/birds')
@ -299,7 +300,19 @@ var BaseTagsPrototype = {
// XXX Q: should definitions be displayed as persistent tags??? // XXX Q: should definitions be displayed as persistent tags???
definitions: null, definitions: null,
// definitions as paths... // Props...
//
// Number of values...
get length(){
return this.values().length },
// Definitions as paths...
//
// Each definition is effectively a path in the following form:
// <value>/<tag>
//
// Example:
// .define('tag', 'concept:tag') // -> 'concept:tag/tag'
// //
// XXX do we need this??? // XXX do we need this???
// XXX should we cache this??? // XXX should we cache this???
@ -308,12 +321,13 @@ var BaseTagsPrototype = {
.map(function(e){ .map(function(e){
return [e[1].join(':'), e[0]].join('/') }) }, return [e[1].join(':'), e[0]].join('/') }) },
// All persistent tags...
// Props...
// //
get length(){ // This will include:
return this.values().length }, // .persistent
// XXX should this include only definition keys, values or both??? // .definition_paths
//
// XXX do we need this???
get persistentAll(){ get persistentAll(){
return (this.__persistent || new Set()) return (this.__persistent || new Set())
.unite(this.definition_paths || []) }, .unite(this.definition_paths || []) },
@ -349,21 +363,32 @@ var BaseTagsPrototype = {
// -> tags // -> tags
// //
// //
// Query syntax: // This takes tag definitions into account when matching, but does
// a - tag // not account for persistent tags (see: .match(..)).
// a/b - path, defines a directional relation between a and b // This does not build the path graph... (XXX)
// /a - path special case, matches iff a is at path root //
// a/ - path special case, matches iff a is at path base //
// a:b - set, defines a non-directional relation between a and b // Query syntax:
// * - tag placeholder, matches one and only one tag name // a - single tag
// NOTE: a tag is also a unary path and a singular
// set (see below).
// a/b - path, 2 or more tags joined with '/' (or '\').
// defines a directional relation between a and b
// /a - path special case, a path with a leading '/' (or '\')
// a/ - path special case, a path with a trailing '/' (or '\')
// a:b - set, two or more tags joined with ':'
// defines a non-directional relation between a and b.
// * - tag placeholder, matches one and only one tag
// //
// NOTE: a tag is also a singular path and a singular set.
// NOTE: paths have priority over sets: a/b:c -> a / b:c // NOTE: paths have priority over sets: a/b:c -> a / b:c
// NOTE: there is a special case pattern '*a*' that matches the same // NOTE: there is a special case pattern '*a*' that matches the same
// way as 'a', this is used in cases where 'a' is used as an // way as 'a', this is used in methods where 'a' is used as an
// explicit match (see: .untag(..)) // explicit 1:1 match (see: .untag(..))
// //
// //
//
// Matching:
//
// Two paths match iff: // Two paths match iff:
// - all of the components of the first are contained in the second and // - all of the components of the first are contained in the second and
// - component order is maintained. // - component order is maintained.
@ -380,6 +405,12 @@ var BaseTagsPrototype = {
// a/b a/b b/a // a/b a/b b/a
// x/a/y/b/z b/x // x/a/y/b/z b/x
// ... ... // ... ...
// --------------------------------
// /a a/b/c b/a/c
// ... ...
// --------------------------------
// a/ x/y/a a/x
// ... ...
// //
// //
// Two sets match iff: // Two sets match iff:
@ -399,19 +430,16 @@ var BaseTagsPrototype = {
// a:x:b:z ... // a:x:b:z ...
// ... // ...
// //
//
// 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 //
// given tags, to search taking paths into account use .match(..)
directMatch: function(a, b, cmp){ directMatch: function(a, b, cmp){
var that = this var that = this
if(b instanceof Function){ if(b instanceof Function){
cmp = b cmp = b
b = null b = null
} }
// get matching tags... // no given tags or multiple tags -> filter...
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){
@ -424,7 +452,6 @@ var BaseTagsPrototype = {
var root = /^\s*[\\\/]/.test(a) var root = /^\s*[\\\/]/.test(a)
var base = /[\\\/]\s*$/.test(a) var base = /[\\\/]\s*$/.test(a)
// normalized match...
a = this.normalize(a) a = this.normalize(a)
// special case: *tag* pattern... // special case: *tag* pattern...
a = /^\*[^:\\\/]*\*$/.test(a) ? a = /^\*[^:\\\/]*\*$/.test(a) ?
@ -432,6 +459,7 @@ var BaseTagsPrototype = {
: a : a
b = this.normalize(b) b = this.normalize(b)
// the fast case...
if(a == b){ if(a == b){
return true return true
} }
@ -503,10 +531,10 @@ var BaseTagsPrototype = {
} }
}, },
// Match tags directly or indirectly... // Match tags...
// //
// This is the same as .directMatch(..) but also uses paths to check // This is the same as .directMatch(..) but also uses persistent
// tag "reachability"... // tags and path graph to check tag "reachability"...
// //
// Matching rule: // Matching rule:
// a and b match iff both a and b are reachable on a single path // a and b match iff both a and b are reachable on a single path
@ -531,6 +559,8 @@ var BaseTagsPrototype = {
// ts.match('c', 'a') // -> false // ts.match('c', 'a') // -> false
// //
// //
// XXX MUG: the path graph search seems to happen iff all of the needed
// chains are actually used to tag values...
match: function(a, b, cmp){ match: function(a, b, cmp){
var that = this var that = this
@ -542,7 +572,8 @@ var BaseTagsPrototype = {
var paths = function(tag){ var paths = function(tag){
return that.directMatch(tag, cmp) return that.directMatch(tag, cmp)
.filter(function(t){ .filter(function(t){
return that.PATH_SEPARATOR.test(t) }) } return /[\\\/]/.test(t) }) }
//return that.PATH_SEPARATOR.test(t) }) }
// search the path tree... // search the path tree...
// NOTE: this will stop the search on first hit... // NOTE: this will stop the search on first hit...
var search = function(tag, seen){ var search = function(tag, seen){
@ -569,6 +600,28 @@ var BaseTagsPrototype = {
false false
: search(tag, seen.add(tag)) }, false) }, false) } : search(tag, seen.add(tag)) }, false) }, false) }
/* // XXX is this faster???
var reachable = function(tag, seen){
seen = seen || new Set()
seen.add(tag)
// list of directly reachable tags...
var r = paths(tag)
.map(function(path){
console.log(' p:', path)
path = that.splitPath(path)
return path.slice(0, path.indexOf(tag)) })
.flat()
.filter(function(tag){
return !seen.has(tag) })
return r.includes(a)
|| r.reduce(function(res, tag){
return res
|| reachable(tag, seen) }, false)
}
//*/
var res = this.directMatch(...arguments) var res = this.directMatch(...arguments)
return res === false ? return res === false ?
search(b) search(b)