reworked .aliases into .definitions and added them to matching...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2018-12-17 19:38:12 +03:00
parent d0a89fc507
commit 8c58a825d1

View File

@ -235,7 +235,7 @@ var BaseTagsPrototype = {
// //
persistent: null, persistent: null,
// Tag aliases... // Tag definitions...
// //
// Format: // Format:
// { // {
@ -243,7 +243,7 @@ var BaseTagsPrototype = {
// ... // ...
// } // }
// //
aliases: null, definitions: null,
// Utils... // Utils...
@ -342,28 +342,41 @@ var BaseTagsPrototype = {
// match two tags... // match two tags...
} else { } else {
var definitions = this.definitions
var root = /^\s*[\\\/]/.test(a) var root = /^\s*[\\\/]/.test(a)
var base = /[\\\/]\s*$/.test(a) var base = /[\\\/]\s*$/.test(a)
// normalized match... // normalized match...
a = this.normalize(a) a = this.normalize(a)
b = this.normalize(b)
// special case: *tag* pattern... // special case: *tag* pattern...
a = /^\*[^:\\\/]*\*$/.test(a) ? a = /^\*[^:\\\/]*\*$/.test(a) ?
a.slice(1, -1) a.slice(1, -1)
: a : a
b = this.normalize(b)
if(a == b){ if(a == b){
return true return true
} }
// set matching... // set/definition 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 matches single tags too...
var matchSet = function(a, b){ var matchSet = function(a, b){
a = a.split(/:/g) a = a.split(/:/g)
b = b.split(/:/g) b = b.split(/:/g)
// extend b with definitions...
b = b
.concat(!definitions ? [] : (b
.map(function(v){
return v in definitions ?
definitions[v].split(/:/g)
: [] })
.flat()))
return a.length <= b.length return a.length <= b.length
// keep only the non-matches -> if at least one exists we fail...
&& a.filter(function(e){ && a.filter(function(e){
return e != '*' return e != '*'
&& b.indexOf(e) < 0 && b.indexOf(e) < 0
@ -428,16 +441,15 @@ var BaseTagsPrototype = {
match: function(a, b, cmp){ match: function(a, b, cmp){
var that = this var that = this
var edge = /^\s*[\\\/]/.test(a) || /[\\\/]\s*$/.test(a) // root or base?
var edge = /^\s*[\\\/]/.test(a)
var res = this.directMatch(...arguments) || /[\\\/]\s*$/.test(a)
// get paths with tag... // get paths with tag...
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 /[\\\/]/.test(t) }) } return /[\\\/]/.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){
@ -464,6 +476,7 @@ var BaseTagsPrototype = {
false false
: search(tag, seen.add(tag)) }, false) }, false) } : search(tag, seen.add(tag)) }, false) }, false) }
var res = this.directMatch(...arguments)
return res === false ? return res === false ?
search(b) search(b)
: res : res
@ -586,6 +599,7 @@ var BaseTagsPrototype = {
get length(){ get length(){
return this.values().length }, return this.values().length },
// Direct tag/value check...
// XXX can these be faster??? // XXX can these be faster???
// XXX should these take multiple values??? // XXX should these take multiple values???
hasTag: function(tag){ hasTag: function(tag){
@ -696,22 +710,34 @@ var BaseTagsPrototype = {
// Edit API... // Edit API...
// //
// Get/set/remove tag definitions...
// //
// Resolve alias (recursive)... // A definition is a single tag that is defined by ("means") a tag set.
//
// Resolve definition (recursive)...
// .alias(tag) // .alias(tag)
// -> value // -> value
// -> undefined // -> undefined
// //
// Set alias... // Set definition...
// .alias(tag, value) // .alias(tag, value)
// -> this // -> this
// //
// Remove alias... // Remove definition...
// .alias(tag, null) // .alias(tag, null)
// -> this // -> this
// //
alias: function(tag, value){ //
var aliases = this.aliases = this.aliases || {} // Example:
// ts.define('birds', 'bird:many')
//
// ts.match('bird', ['bird', 'birds', 'animal']) // -> ['bird', 'birds']
//
//
// XXX revise recursion testing and if it is needed...
define: function(tag, value){
var definitions = this.definitions = this.definitions || {}
// 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 || []
@ -721,8 +747,8 @@ var BaseTagsPrototype = {
seen seen
.concat([seen[0]]) .concat([seen[0]])
.join('" -> "') }"`) } .join('" -> "') }"`) }
var next = aliases[tag] var next = definitions[tag]
|| aliases[this.normalize(tag)] || definitions[this.normalize(tag)]
seen.push(tag) seen.push(tag)
return next != null ? return next != null ?
resolve(next, seen) resolve(next, seen)
@ -731,19 +757,23 @@ var BaseTagsPrototype = {
: undefined : undefined
}.bind(this) }.bind(this)
tag = this.normalize(tag)
if(/[:\\\/]/.test(tag)){
throw new Error(`.alias(..): tag must be a single tag, got: "${tag}`) }
// resolve... // resolve...
if(arguments.length == 1){ if(arguments.length == 1){
return resolve(tag.trim()) return resolve(tag)
// remove... // remove...
} else if(value == null){ } else if(value == null){
delete aliases[tag.trim()] delete definitions[tag]
delete aliases[this.normalize(tag)]
// set... // set...
} else { } else {
tag = tag.trim()
value = this.normalize(value) value = this.normalize(value)
if(/[\\\/]/.test(tag)){
throw new Error(`.alias(..): value must not be a path, got: "${value}`) }
// check for recursion... // check for recursion...
var chain = [] var chain = []
@ -754,12 +784,11 @@ var BaseTagsPrototype = {
.concat([chain[0]]) .concat([chain[0]])
.join('" -> "') }"`) } .join('" -> "') }"`) }
aliases[tag] = value definitions[tag] = value
} }
return this return this
}, },
// XXX save un-normalized tags as aliases... ??? // XXX save un-normalized tags to dict... ???
// 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
value = value instanceof Array ? value : [value] value = value instanceof Array ? value : [value]
@ -1017,7 +1046,7 @@ var BaseTagsPrototype = {
} else { } else {
patchSet(this.persistent || []) patchSet(this.persistent || [])
patchObj(this.__index || {}) patchObj(this.__index || {})
patchObj(this.aliases || {}, true) patchObj(this.definitions || {}, true)
} }
return this return this
@ -1414,8 +1443,8 @@ var BaseTagsPrototype = {
// Format: // Format:
// { // {
// // optional // // optional
// aliases: null | { // definitions: null | {
// <alias>: <value>, // <single-tag>: <tag-set>,
// ... // ...
// }, // },
// //
@ -1437,9 +1466,9 @@ var BaseTagsPrototype = {
json: function(){ json: function(){
var res = {} var res = {}
// aliases... // definitions...
this.aliases && Object.keys(this.aliases).length > 0 this.definitions && Object.keys(this.definitions).length > 0
&& (res.aliases = Object.assign({}, this.aliases)) && (res.definitions = Object.assign({}, this.definitions))
// persistent tags... // persistent tags...
this.persistent && this.persistent.size > 0 this.persistent && this.persistent.size > 0
@ -1457,9 +1486,9 @@ var BaseTagsPrototype = {
load: function(json){ load: function(json){
var that = this var that = this
// aliases... // definitions...
json.aliases json.definitions
&& (this.aliases = Object.assign({}, json.aliases)) && (this.definitions = Object.assign({}, json.definitions))
// persistent tags... // persistent tags...
json.persistent json.persistent