mirror of
https://github.com/flynx/ImageGrid.git
synced 2025-10-29 10:20:08 +00:00
now support recursive deffinitions...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
7722b881ff
commit
7784794e45
@ -20,7 +20,8 @@
|
|||||||
* - will it be faster?
|
* - will it be faster?
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* XXX should we .optimizeTags(tag) on .tag(tag)???
|
* XXX should we do .optimizeTags(tag) on .tag(tag)???
|
||||||
|
* ...this might lead to non-trivial behaviour...
|
||||||
* XXX should this serialize recursively down???
|
* XXX should this serialize recursively down???
|
||||||
* ...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...
|
||||||
@ -224,7 +225,8 @@ var BaseTagsClassPrototype = {
|
|||||||
// XXX should we store normalized and non-normalized tags for reference???
|
// XXX should we store normalized and non-normalized tags for reference???
|
||||||
// ...there are two ways to think of this:
|
// ...there are two ways to think of this:
|
||||||
// 1) both (a-la flickr) -- keep both, use normalized internally
|
// 1) both (a-la flickr) -- keep both, use normalized internally
|
||||||
// 2) only normalized -- simpler but may surprise the user and not be as pretty...
|
// 2) only normalized -- simpler but may surprise the user and
|
||||||
|
// not be as pretty...
|
||||||
// XXX should we split out the non-basic stuff???
|
// XXX should we split out the non-basic stuff???
|
||||||
// like:
|
// like:
|
||||||
// .makePathsPersistent()
|
// .makePathsPersistent()
|
||||||
@ -271,28 +273,15 @@ var BaseTagsPrototype = {
|
|||||||
|
|
||||||
// Utils...
|
// Utils...
|
||||||
//
|
//
|
||||||
// XXX should these be proxies or simply refs???
|
// NOTE: these are not proxies to .constructor so as to make the
|
||||||
// - proxies would make it possible to change stuff in the
|
// instance largely independent of its constructor and thus
|
||||||
// constructor and affect all the instances...
|
// making it possible to use it as a mix-in (copy methods)
|
||||||
// - refs would make things a bit faster but would isolate
|
// and other approaches...
|
||||||
// the instances from the constructor...
|
|
||||||
splitSet: BaseTagsClassPrototype.splitSet,
|
splitSet: BaseTagsClassPrototype.splitSet,
|
||||||
splitPath: BaseTagsClassPrototype.splitPath,
|
splitPath: BaseTagsClassPrototype.splitPath,
|
||||||
normalize: BaseTagsClassPrototype.normalize,
|
normalize: BaseTagsClassPrototype.normalize,
|
||||||
subTags: BaseTagsClassPrototype.subTags,
|
subTags: BaseTagsClassPrototype.subTags,
|
||||||
parseQuery: BaseTagsClassPrototype.parseQuery,
|
parseQuery: BaseTagsClassPrototype.parseQuery,
|
||||||
/*// proxies to class methods...
|
|
||||||
splitSet: function(str){
|
|
||||||
return this.constructor.splitSet.call(this, str) },
|
|
||||||
splitPath: function(str){
|
|
||||||
return this.constructor.splitPath.call(this, str) },
|
|
||||||
normalize: function(...tags){
|
|
||||||
return this.constructor.normalize.call(this, ...tags) },
|
|
||||||
subTags: function(...tags){
|
|
||||||
return this.constructor.subTags.call(this, ...tags) },
|
|
||||||
parseQuery: function(query){
|
|
||||||
return this.constructor.parseQuery.call(this, query) },
|
|
||||||
//*/
|
|
||||||
|
|
||||||
|
|
||||||
// Tag matching and filtering...
|
// Tag matching and filtering...
|
||||||
@ -399,22 +388,36 @@ var BaseTagsPrototype = {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// set/definition matching...
|
// Expand definitions...
|
||||||
|
//
|
||||||
|
// NOTE: this does not care about infinite recursion...
|
||||||
|
var expand = function(tags, res){
|
||||||
|
if(!definitions){
|
||||||
|
return tags
|
||||||
|
}
|
||||||
|
res = (res || new Set()).unite(tags)
|
||||||
|
|
||||||
|
tags = tags
|
||||||
|
.map(function(tag){
|
||||||
|
return tag in definitions ?
|
||||||
|
definitions[tag]
|
||||||
|
: [] })
|
||||||
|
.flat()
|
||||||
|
|
||||||
|
var size = res.size
|
||||||
|
res = res.unite(tags)
|
||||||
|
return res.size != size ?
|
||||||
|
expand(tags, res)
|
||||||
|
: [...res]
|
||||||
|
}
|
||||||
|
// Set matching...
|
||||||
// a matches b iff each element of a exists in b.
|
// a matches b iff each element of a exists in b.
|
||||||
//
|
//
|
||||||
// NOTE: this does not care about order...
|
// NOTE: this does not care about order...
|
||||||
// NOTE: this matches single tags too...
|
// NOTE: this matches single tags too...
|
||||||
var matchSet = function(a, b){
|
var matchSet = function(a, b){
|
||||||
a = that.splitSet(a)
|
a = that.splitSet(a)
|
||||||
b = that.splitSet(b)
|
b = expand(that.splitSet(b))
|
||||||
// extend b with definitions...
|
|
||||||
b = b
|
|
||||||
.concat(!definitions ? [] : (b
|
|
||||||
.map(function(v){
|
|
||||||
return v in definitions ?
|
|
||||||
definitions[v]
|
|
||||||
: [] })
|
|
||||||
.flat()))
|
|
||||||
return a.length <= b.length
|
return a.length <= b.length
|
||||||
// keep only the non-matches -> if at least one exists we fail...
|
// keep only the non-matches -> if at least one exists we fail...
|
||||||
&& a.filter(function(e){
|
&& a.filter(function(e){
|
||||||
@ -640,24 +643,20 @@ var BaseTagsPrototype = {
|
|||||||
return this.values().length },
|
return this.values().length },
|
||||||
|
|
||||||
// Direct tag/value check...
|
// Direct tag/value check...
|
||||||
// XXX can these be faster???
|
//
|
||||||
|
// NOTE: these are not using for loops so as to enable "fast abort",
|
||||||
|
// not sure who much performance this actually gains though.
|
||||||
// XXX should these take multiple values???
|
// XXX should these take multiple values???
|
||||||
hasTag: function(tag){
|
hasTag: function(tag){
|
||||||
for(var t of this.tags()){
|
for(var t of this.tags()){
|
||||||
if(this.match(tag, t)){
|
if(this.match(tag, t)){
|
||||||
return true
|
return true } }
|
||||||
}
|
return false },
|
||||||
}
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
has: function(value){
|
has: function(value){
|
||||||
for(var v of Object.values(this.__index || {})){
|
for(var v of Object.values(this.__index || {})){
|
||||||
if(v.has(value)){
|
if(v.has(value)){
|
||||||
return true
|
return true } }
|
||||||
}
|
return false },
|
||||||
}
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
|
|
||||||
// Tags present in the system...
|
// Tags present in the system...
|
||||||
//
|
//
|
||||||
@ -675,12 +674,13 @@ var BaseTagsPrototype = {
|
|||||||
// .tags(value, [tag, ..])
|
// .tags(value, [tag, ..])
|
||||||
// -> bool
|
// -> bool
|
||||||
//
|
//
|
||||||
//
|
// NOTE: this will return the list of actual tags used and will not
|
||||||
|
// generate any new values (like .singleTags(..) and friends do).
|
||||||
// NOTE: this includes all the persistent tags as well as all the
|
// NOTE: this includes all the persistent tags as well as all the
|
||||||
// tags actually used.
|
// tags actually used.
|
||||||
//
|
//
|
||||||
// XXX should this return split values / combined with .singleTags(..)???
|
// XXX should we rename this to .usedTags(..) and .singleTags(..) to
|
||||||
// i.e. 'red:car' -> ['red', 'car']
|
// .tags(..) ???
|
||||||
tags: function(value, ...tags){
|
tags: function(value, ...tags){
|
||||||
var that = this
|
var that = this
|
||||||
|
|
||||||
@ -749,7 +749,7 @@ var BaseTagsPrototype = {
|
|||||||
tag: function(tags, value){
|
tag: function(tags, value){
|
||||||
var that = this
|
var that = this
|
||||||
value = value instanceof Array ? value : [value]
|
value = value instanceof Array ? value : [value]
|
||||||
tags = this.normalize(tags)
|
tags = this.normalize(tags instanceof Array ? tags : [tags])
|
||||||
var index = this.__index = this.__index || {}
|
var index = this.__index = this.__index || {}
|
||||||
|
|
||||||
tags
|
tags
|
||||||
@ -768,7 +768,7 @@ var BaseTagsPrototype = {
|
|||||||
value = value instanceof Array ? value : [value]
|
value = value instanceof Array ? value : [value]
|
||||||
|
|
||||||
this
|
this
|
||||||
.normalize(tags)
|
.normalize(tags instanceof Array ? tags : [tags])
|
||||||
// resolve/match tags...
|
// resolve/match tags...
|
||||||
.map(function(tag){
|
.map(function(tag){
|
||||||
return /\*/.test(tag) ?
|
return /\*/.test(tag) ?
|
||||||
@ -935,7 +935,7 @@ var BaseTagsPrototype = {
|
|||||||
//
|
//
|
||||||
// XXX need to sanitize tag -- it can not contain regex characters...
|
// XXX need to sanitize tag -- it can not contain regex characters...
|
||||||
// ...should we guard against this???
|
// ...should we guard against this???
|
||||||
// XXX should both sides of the alias be renamed???
|
// XXX should both sides of the definition be renamed???
|
||||||
rename: function(tag, to, ...tags){
|
rename: function(tag, to, ...tags){
|
||||||
var that = this
|
var that = this
|
||||||
|
|
||||||
@ -1066,12 +1066,23 @@ var BaseTagsPrototype = {
|
|||||||
// -> this
|
// -> this
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
// Nested recursive definitions (i.e. left side is part of the right
|
||||||
|
// side) are supported, but literal definition recursion are not (i.e.
|
||||||
|
// left side is literally reachable in the definitionchain):
|
||||||
|
// a -> a:b:c - nested (recursive) definition, this is fine.
|
||||||
|
// a -> a - type A literal recursion, this will fail.
|
||||||
|
// a -> b -> a - type B literal recursion will fail too.
|
||||||
|
//
|
||||||
|
//
|
||||||
// Example:
|
// Example:
|
||||||
|
// // nested recursive definition...
|
||||||
|
// ts.define('bird', 'bird:one')
|
||||||
|
//
|
||||||
// ts.define('birds', 'bird:many')
|
// ts.define('birds', 'bird:many')
|
||||||
//
|
//
|
||||||
|
// // filter a list...
|
||||||
// ts.match('bird', ['bird', 'birds', 'animal']) // -> ['bird', 'birds']
|
// ts.match('bird', ['bird', 'birds', 'animal']) // -> ['bird', 'birds']
|
||||||
//
|
//
|
||||||
// XXX revise recursion testing and if it is needed...
|
|
||||||
define: function(tag, value){
|
define: function(tag, value){
|
||||||
var definitions = this.definitions = this.definitions || {}
|
var definitions = this.definitions = this.definitions || {}
|
||||||
|
|
||||||
@ -1088,7 +1099,7 @@ var BaseTagsPrototype = {
|
|||||||
|| definitions[this.normalize(tag)]
|
|| definitions[this.normalize(tag)]
|
||||||
seen.push(tag)
|
seen.push(tag)
|
||||||
return next != null ?
|
return next != null ?
|
||||||
resolve(next, seen)
|
resolve(next.join(':'), seen)
|
||||||
: seen.length > 1 ?
|
: seen.length > 1 ?
|
||||||
tag
|
tag
|
||||||
: undefined
|
: undefined
|
||||||
@ -1536,6 +1547,7 @@ var BaseTagsPrototype = {
|
|||||||
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
var BaseTags =
|
var BaseTags =
|
||||||
module.BaseTags =
|
module.BaseTags =
|
||||||
object.makeConstructor('BaseTags',
|
object.makeConstructor('BaseTags',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user