started real work on tags...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2018-11-26 01:01:50 +03:00
parent a0767d3c11
commit 210ad80c3d

View File

@ -30,9 +30,17 @@ var TagsClassPrototype = {
// .normalize([tag, ...]) // .normalize([tag, ...])
// -> [ntag, ...] // -> [ntag, ...]
// //
// XXX should this sort sets??? // NOTE: tag set order is not significant.
// NOTE: for mixed tags sets are sorted in-place within paths,
// e.g.
// c:b/a -> b:c/a
//
// XXX not sure if we should do:
// c:b/a -> b:c/a - sort sets within pats (current)
// or
// c:b/a -> b/a:c - sort paths within sets
// XXX should this be .normalizeTags(..) ??? // XXX should this be .normalizeTags(..) ???
// XXX should this resolve aliases??? // XXX should we support priority braces, i.e. c:(b/a)
normalize: function(...tags){ normalize: function(...tags){
var that = this var that = this
var tagRemovedChars = (this.config || {})['tagRemovedChars'] var tagRemovedChars = (this.config || {})['tagRemovedChars']
@ -50,10 +58,18 @@ var TagsClassPrototype = {
.trim() .trim()
.toLowerCase() .toLowerCase()
.replace(tagRemovedChars, '') .replace(tagRemovedChars, '')
// XXX do we need to sort here??? // sort sets within paths...
.split(/:/) .split(/[\\\/]/g)
.sort() .map(function(e){
.join(':') }) return e
.split(/:/g)
.sort()
.join(':') })
.join('/') })
// sort paths within sets...
//.split(/:/g)
// .sort()
// .join(':') })
.unique() .unique()
return (tags.length == 1 && !(tags[0] instanceof Array)) ? return (tags.length == 1 && !(tags[0] instanceof Array)) ?
// NOTE: if we got a single tag return it as a single tag... // NOTE: if we got a single tag return it as a single tag...
@ -88,14 +104,7 @@ var TagsPrototype = {
// [ <tag>, ... ] // [ <tag>, ... ]
// //
// XXX Q: should these be normalized??? // XXX Q: should these be normalized???
__persistent_tags: [], __persistent_tags: null,
// Format:
// {
// <tag>: [ <item>, ... ],
// ...
// }
__index: {},
// Format: // Format:
// { // {
@ -104,7 +113,14 @@ var TagsPrototype = {
// //
// XXX need introspection for this... // XXX need introspection for this...
// ...should this be .aliases ??? // ...should this be .aliases ???
__aliases: {}, __aliases: null,
// Format:
// {
// <tag>: [ <item>, ... ],
// ...
// }
__index: null,
// Utils... // Utils...
@ -113,37 +129,106 @@ var TagsPrototype = {
// XXX Q: should this be .normalizeTags(..) ??? // XXX Q: should this be .normalizeTags(..) ???
normalize: function(...tags){ normalize: function(...tags){
return this.constructor.normalize.call(this, ...tags) }, return this.constructor.normalize.call(this, ...tags) },
// Match two tags...
// XXX expand aliases...
// XXX
get length(){
// XXX number of elements (values)...
},
// Tags present in the system...
// //
// NOTE: this includes all the .persistent tags as well as all the // NOTE: this is not symmetric e.g. a will match a:b but not vice-versa.
// tags actually used. //
tags: function(){ // XXX add support for * in sets...
// XXX match: function(a, b){
// normalized match...
a = this.normalize(a)
b = this.normalize(b)
if(a == b){
return true
}
// set matching...
// a matches b iff each element of a exists in b.
var matchSet = function(a, b){
a = a.split(/:/g)
b = b.split(/:/g)
return a
.filter(function(e){
return e == '*'
|| b.indexOf(e) < 0 }).length == 0 }
// path matching...
// a matches b iff each element in a exists in b and in the same
// order as in a.
a = a.split(/[\/\\]/g)
b = b.split(/[\/\\]/g)
return b
.reduce(function(a, e){
return a[0] && matchSet(a[0], e) ?
a.slice(1)
: a
}, a).length == 0
}, },
// Introspection...
//
get length(){
return this.values().length },
// XXX need a way to add/remove these... // XXX need a way to add/remove these...
persistent: function(){ persistent: function(){
// XXX // XXX
}, },
values: function(){ // Tags present in the system...
// XXX //
// Get all tags...
// .tags()
// -> tags
//
// Get value tags...
// .tags(value)
// -> tags
//
// NOTE: this includes all the .persistent tags as well as all the
// tags actually used.
tags: function(value){
var that = this
// get tags of specific value...
if(value){
return Object.entries(this.__index || {})
.filter(function(e){ return e[1].has(value) })
.map(function(e){ return e[0] })
.flat()
.unique()
// get all tags...
} else {
return Object.keys(this.__index || {})
.concat((this.__persistent_tags || [])
.map(function(t){
return that.normalize(t) }))
.unique()
}
}, },
//
// Get all values...
// .values()
// -> values
//
// Get specific tag values...
// .values(tag)
// -> values
//
// NOTE: this does not support any query syntax...
values: function(tag){
var that = this
tag = this.normalize(tag || '*')
return [...new Set(
Object.entries(this.__index || {})
.filter(function(e){
return tag == '*' || that.match(tag, e[0]) })
.map(function(s){ return [...s[1]] })
.flat())] },
// Add/Remove/Modify tags API... // Add/Remove/Modify tags API...
// XXX
path: function(){
// XXX
return this
},
// //
// Resolve alias (recursive)... // Resolve alias (recursive)...
// .alias(tag) // .alias(tag)
@ -159,6 +244,7 @@ var TagsPrototype = {
// -> this // -> this
// //
alias: function(tag, value){ alias: function(tag, value){
var aliases = this.__aliases = this.__aliases || {}
// XXX this seems a bit ugly... // XXX this seems a bit ugly...
var resolve = function(tag, seen){ var resolve = function(tag, seen){
seen = seen || [] seen = seen || []
@ -168,8 +254,8 @@ var TagsPrototype = {
seen seen
.concat([seen[0]]) .concat([seen[0]])
.join('" -> "') }"`) } .join('" -> "') }"`) }
var next = this.__aliases[tag] var next = aliases[tag]
|| this.__aliases[this.normalize(tag)] || aliases[this.normalize(tag)]
seen.push(tag) seen.push(tag)
return next != null ? return next != null ?
resolve(next, seen) resolve(next, seen)
@ -184,8 +270,8 @@ var TagsPrototype = {
// remove... // remove...
} else if(value == null){ } else if(value == null){
delete this.__aliases[tag.trim()] delete aliases[tag.trim()]
delete this.__aliases[this.normalize(tag)] delete aliases[this.normalize(tag)]
// set... // set...
} else { } else {
@ -201,20 +287,35 @@ var TagsPrototype = {
.concat([chain[0]]) .concat([chain[0]])
.join('" -> "') }"`) } .join('" -> "') }"`) }
this.__aliases[tag] = value aliases[tag] = value
} }
return this return this
}, },
// Add/Remove/Modify content API... // Add/Remove/Modify content API...
// XXX //
tag: function(){ // XXX save un-normalized tags as aliases...
// XXX // XXX when value is not given, add tags to persistent tags...
tag: function(tags, value){
var that = this
this.__index = this.__index || {}
this.normalize(tags instanceof Array ? tags : [tags])
.forEach(function(tag){
(that.__index[tag] = that.__index[tag] || new Set()).add(value) })
return this return this
}, },
untag: function(){ untag: function(tags, value){
// XXX var that = this
this.normalize(tags instanceof Array ? tags : [tags])
.forEach(function(tag){
var s = that.__index[tag] || new Set()
s.delete(value)
// remove empty sets...
if(s.size == 0){
delete that.__index[tag]
}
})
return this return this
}, },