mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-06-24 22:33:16 +00:00
Multiple operands for filter operators (#4964)
* Firt pass at adding multiple operands to filter operators * Optimized parsing of multiple operands and added more tests. Need more flexibility for interpreting multiple operands as variables/text references * Add support for parsing text references and variables in multiple operands * Added string-replace filter for testing multiple filter operands * Added more tests for variables and text references in operands * Removed string-replace operator and some whitespace corrections * Removed string-replace operator and some whitespace corrections * Added test with comma in operand
This commit is contained in:
parent
0bd866e2f9
commit
2b31c7a509
|
@ -62,43 +62,61 @@ function parseFilterOperation(operators,filterString,p) {
|
||||||
else if(operator.operator === "") {
|
else if(operator.operator === "") {
|
||||||
operator.operator = "title";
|
operator.operator = "title";
|
||||||
}
|
}
|
||||||
|
operator.operands = [];
|
||||||
|
function parseOperand(bracketType) {
|
||||||
|
var operand = {};
|
||||||
|
switch (bracketType) {
|
||||||
|
case "{": // Curly brackets
|
||||||
|
operand.indirect = true;
|
||||||
|
nextBracketPos = filterString.indexOf("}",p);
|
||||||
|
break;
|
||||||
|
case "[": // Square brackets
|
||||||
|
nextBracketPos = filterString.indexOf("]",p);
|
||||||
|
break;
|
||||||
|
case "<": // Angle brackets
|
||||||
|
operand.variable = true;
|
||||||
|
nextBracketPos = filterString.indexOf(">",p);
|
||||||
|
break;
|
||||||
|
case "/": // regexp brackets
|
||||||
|
var rex = /^((?:[^\\\/]*|\\.)*)\/(?:\(([mygi]+)\))?/g,
|
||||||
|
rexMatch = rex.exec(filterString.substring(p));
|
||||||
|
if(rexMatch) {
|
||||||
|
operator.regexp = new RegExp(rexMatch[1], rexMatch[2]);
|
||||||
|
// DEPRECATION WARNING
|
||||||
|
console.log("WARNING: Filter",operator.operator,"has a deprecated regexp operand",operator.regexp);
|
||||||
|
nextBracketPos = p + rex.lastIndex - 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw "Unterminated regular expression in filter expression";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nextBracketPos === -1) {
|
||||||
|
throw "Missing closing bracket in filter expression";
|
||||||
|
}
|
||||||
|
if(!operator.regexp) {
|
||||||
|
operand.text = filterString.substring(p,nextBracketPos);
|
||||||
|
operator.operands.push(operand);
|
||||||
|
}
|
||||||
|
p = nextBracketPos + 1;
|
||||||
|
}
|
||||||
|
|
||||||
p = nextBracketPos + 1;
|
p = nextBracketPos + 1;
|
||||||
switch (bracket) {
|
parseOperand(bracket);
|
||||||
case "{": // Curly brackets
|
|
||||||
operator.indirect = true;
|
// Check for multiple operands
|
||||||
nextBracketPos = filterString.indexOf("}",p);
|
while(filterString.charAt(p) === ",") {
|
||||||
break;
|
p++;
|
||||||
case "[": // Square brackets
|
if(/^[\[\{<\/]/.test(filterString.substring(p))) {
|
||||||
nextBracketPos = filterString.indexOf("]",p);
|
nextBracketPos = p;
|
||||||
break;
|
p++;
|
||||||
case "<": // Angle brackets
|
parseOperand(filterString.charAt(nextBracketPos));
|
||||||
operator.variable = true;
|
} else {
|
||||||
nextBracketPos = filterString.indexOf(">",p);
|
throw "Missing [ in filter expression";
|
||||||
break;
|
}
|
||||||
case "/": // regexp brackets
|
|
||||||
var rex = /^((?:[^\\\/]*|\\.)*)\/(?:\(([mygi]+)\))?/g,
|
|
||||||
rexMatch = rex.exec(filterString.substring(p));
|
|
||||||
if(rexMatch) {
|
|
||||||
operator.regexp = new RegExp(rexMatch[1], rexMatch[2]);
|
|
||||||
// DEPRECATION WARNING
|
|
||||||
console.log("WARNING: Filter",operator.operator,"has a deprecated regexp operand",operator.regexp);
|
|
||||||
nextBracketPos = p + rex.lastIndex - 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw "Unterminated regular expression in filter expression";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nextBracketPos === -1) {
|
|
||||||
throw "Missing closing bracket in filter expression";
|
|
||||||
}
|
|
||||||
if(!operator.regexp) {
|
|
||||||
operator.operand = filterString.substring(p,nextBracketPos);
|
|
||||||
}
|
|
||||||
p = nextBracketPos + 1;
|
|
||||||
|
|
||||||
// Push this operator
|
// Push this operator
|
||||||
operators.push(operator);
|
operators.push(operator);
|
||||||
} while(filterString.charAt(p) !== "]");
|
} while(filterString.charAt(p) !== "]");
|
||||||
|
@ -152,7 +170,7 @@ exports.parseFilter = function(filterString) {
|
||||||
}
|
}
|
||||||
if(match[4] || match[5] || match[6]) { // Double quoted string, single quoted string or unquoted title
|
if(match[4] || match[5] || match[6]) { // Double quoted string, single quoted string or unquoted title
|
||||||
operation.operators.push(
|
operation.operators.push(
|
||||||
{operator: "title", operand: match[4] || match[5] || match[6]}
|
{operator: "title", operands: [{text: match[4] || match[5] || match[6]}]}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
results.push(operation);
|
results.push(operation);
|
||||||
|
@ -209,7 +227,7 @@ exports.compileFilter = function(filterString) {
|
||||||
results = [],
|
results = [],
|
||||||
currTiddlerTitle = widget && widget.getVariable("currentTiddler");
|
currTiddlerTitle = widget && widget.getVariable("currentTiddler");
|
||||||
$tw.utils.each(operation.operators,function(operator) {
|
$tw.utils.each(operation.operators,function(operator) {
|
||||||
var operand = operator.operand,
|
var operands = [],
|
||||||
operatorFunction;
|
operatorFunction;
|
||||||
if(!operator.operator) {
|
if(!operator.operator) {
|
||||||
operatorFunction = filterOperators.title;
|
operatorFunction = filterOperators.title;
|
||||||
|
@ -218,16 +236,23 @@ exports.compileFilter = function(filterString) {
|
||||||
} else {
|
} else {
|
||||||
operatorFunction = filterOperators[operator.operator];
|
operatorFunction = filterOperators[operator.operator];
|
||||||
}
|
}
|
||||||
if(operator.indirect) {
|
|
||||||
operand = self.getTextReference(operator.operand,"",currTiddlerTitle);
|
$tw.utils.each(operator.operands,function(operand) {
|
||||||
}
|
if(operand.indirect) {
|
||||||
if(operator.variable) {
|
operand.value = self.getTextReference(operand.text,"",currTiddlerTitle);
|
||||||
operand = widget.getVariable(operator.operand,{defaultValue: ""});
|
} else if(operand.variable) {
|
||||||
}
|
operand.value = widget.getVariable(operand.text,{defaultValue: ""});
|
||||||
|
} else {
|
||||||
|
operand.value = operand.text;
|
||||||
|
}
|
||||||
|
operands.push(operand.value);
|
||||||
|
});
|
||||||
|
|
||||||
// Invoke the appropriate filteroperator module
|
// Invoke the appropriate filteroperator module
|
||||||
results = operatorFunction(accumulator,{
|
results = operatorFunction(accumulator,{
|
||||||
operator: operator.operator,
|
operator: operator.operator,
|
||||||
operand: operand,
|
operand: operands.length > 0 ? operands[0] : undefined,
|
||||||
|
operands: operands,
|
||||||
prefix: operator.prefix,
|
prefix: operator.prefix,
|
||||||
suffix: operator.suffix,
|
suffix: operator.suffix,
|
||||||
suffixes: operator.suffixes,
|
suffixes: operator.suffixes,
|
||||||
|
|
|
@ -19,19 +19,41 @@ describe("Filter tests", function() {
|
||||||
// Test filter parsing
|
// Test filter parsing
|
||||||
it("should parse new-style rich operator suffixes", function() {
|
it("should parse new-style rich operator suffixes", function() {
|
||||||
expect($tw.wiki.parseFilter("[search:: four, , five,, six [operand]]")).toEqual(
|
expect($tw.wiki.parseFilter("[search:: four, , five,, six [operand]]")).toEqual(
|
||||||
[ { prefix : '', operators : [ { operator : 'search', suffix : ': four, , five,, six ', suffixes : [ [ ], [ 'four', 'five', 'six' ] ], operand : 'operand' } ] } ]
|
[ { prefix : '', operators : [ { operator : 'search', suffix : ': four, , five,, six ', suffixes : [ [ ], [ 'four', 'five', 'six' ] ], operands: [ { text:'operand' } ] } ] } ]
|
||||||
);
|
);
|
||||||
expect($tw.wiki.parseFilter("[search: one, two ,three :[operand]]")).toEqual(
|
expect($tw.wiki.parseFilter("[search: one, two ,three :[operand]]")).toEqual(
|
||||||
[ { prefix : '', operators : [ { operator : 'search', suffix : ' one, two ,three :', suffixes : [ [ 'one', 'two', 'three' ], [ ] ], operand : 'operand' } ] } ]
|
[ { prefix : '', operators : [ { operator : 'search', suffix : ' one, two ,three :', suffixes : [ [ 'one', 'two', 'three' ], [ ] ], operands: [ { text:'operand' } ] } ] } ]
|
||||||
);
|
);
|
||||||
expect($tw.wiki.parseFilter("[search: one, two ,three :[operand]]")).toEqual(
|
expect($tw.wiki.parseFilter("[search: one, two ,three :[operand]]")).toEqual(
|
||||||
[ { prefix : '', operators : [ { operator : 'search', suffix : ' one, two ,three :', suffixes : [ [ 'one', 'two', 'three' ], [ ] ], operand : 'operand' } ] } ]
|
[ { prefix : '', operators : [ { operator : 'search', suffix : ' one, two ,three :', suffixes : [ [ 'one', 'two', 'three' ], [ ] ], operands: [ { text:'operand' } ] } ] } ]
|
||||||
);
|
);
|
||||||
expect($tw.wiki.parseFilter("[search: one, two ,three : four, , five,, six [operand]]")).toEqual(
|
expect($tw.wiki.parseFilter("[search: one, two ,three : four, , five,, six [operand]]")).toEqual(
|
||||||
[ { prefix : '', operators : [ { operator : 'search', suffix : ' one, two ,three : four, , five,, six ', suffixes : [ [ 'one', 'two', 'three' ], [ 'four', 'five', 'six' ] ], operand : 'operand' } ] } ]
|
[ { prefix : '', operators : [ { operator : 'search', suffix : ' one, two ,three : four, , five,, six ', suffixes : [ [ 'one', 'two', 'three' ], [ 'four', 'five', 'six' ] ], operands: [ { text:'operand' } ] } ] } ]
|
||||||
);
|
);
|
||||||
expect($tw.wiki.parseFilter("[search: , : [operand]]")).toEqual(
|
expect($tw.wiki.parseFilter("[search: , : [operand]]")).toEqual(
|
||||||
[ { prefix : '', operators : [ { operator : 'search', suffix : ' , : ', suffixes : [ [ ], [ ] ], operand : 'operand' } ] } ]
|
[ { prefix : '', operators : [ { operator : 'search', suffix : ' , : ', suffixes : [ [ ], [ ] ], operands: [ { text:'operand' } ] } ] } ]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it("should parse multiple operands for operators", function() {
|
||||||
|
expect($tw.wiki.parseFilter("[search: , : [operand],[operand2]]")).toEqual(
|
||||||
|
[ { prefix : '', operators : [ { operator : 'search', suffix : ' , : ', suffixes : [ [ ], [ ] ], operands: [ { text:'operand' }, { text:'operand2' } ] } ] } ]
|
||||||
|
);
|
||||||
|
expect($tw.wiki.parseFilter("[search: , : [oper,and],[operand2]]")).toEqual(
|
||||||
|
[ { prefix : '', operators : [ { operator : 'search', suffix : ' , : ', suffixes : [ [ ], [ ] ], operands: [ { text:'oper,and' }, { text:'operand2' } ] } ] } ]
|
||||||
|
);
|
||||||
|
expect($tw.wiki.parseFilter("[[GettingStarted]replace:[operand],[operand2]]")).toEqual(
|
||||||
|
[ { prefix : '', operators : [ { operator : 'title', operands: [ { text:'GettingStarted' } ] }, { operator : 'replace', suffix : '', suffixes : [[]], operands: [ { text:'operand' }, { text:'operand2' } ] } ] } ]
|
||||||
|
);
|
||||||
|
expect($tw.wiki.parseFilter("[[GettingStarted]replace[operand],[operand2]split[-]]")).toEqual(
|
||||||
|
[ { prefix : '', operators : [ { operator : 'title', operands: [{ text:'GettingStarted' }] }, { operator : 'replace', operands: [{ text:'operand' }, { text:'operand2' }] }, { operator : 'split', operands: [ { text:'-' } ] } ] } ]
|
||||||
|
);
|
||||||
|
expect($tw.wiki.parseFilter("[[GettingStarted]replace[operand],[operand2]split[-]split2[a],[b]]")).toEqual(
|
||||||
|
[ { prefix : '', operators : [ { operator : 'title', operands: [{ text:'GettingStarted' }] }, { operator : 'replace', operands: [ { text:'operand' }, { text:'operand2' } ] }, { operator : 'split', operands: [ {text:'-'} ] }, { operator : 'split2', operands: [ { text:'a' }, { text: 'b' }] } ] } ]
|
||||||
|
);
|
||||||
|
expect($tw.wiki.parseFilter("[[GettingStarted]replace[operand],[operand2]split[-]split2[a],<b>,{c}]")).toEqual(
|
||||||
|
[ { prefix : '', operators : [ { operator : 'title', operands: [{ text:'GettingStarted' }] }, { operator : 'replace', operands: [ { text:'operand' }, { text:'operand2' } ] }, { operator : 'split', operands: [ {text:'-'} ] }, { operator : 'split2', operands: [ { text:'a' }, { variable: true, text: 'b' }, { indirect: true, text: 'c' }] } ] } ]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -730,7 +752,6 @@ function runTests(wiki) {
|
||||||
expect(wiki.filterTiddlers("[!sortsub:string<sort2>]",anchorWidget).join(",")).toBe("filter regexp test,$:/TiddlerTwo,Tiddler Three,a fourth tiddler,$:/ShadowPlugin,has filter,hasList,TiddlerOne,one");
|
expect(wiki.filterTiddlers("[!sortsub:string<sort2>]",anchorWidget).join(",")).toBe("filter regexp test,$:/TiddlerTwo,Tiddler Three,a fourth tiddler,$:/ShadowPlugin,has filter,hasList,TiddlerOne,one");
|
||||||
expect(wiki.filterTiddlers("[[TiddlerOne]] [[$:/TiddlerTwo]] [[Tiddler Three]] [[a fourth tiddler]] +[!sortsub:number<sort3>]",anchorWidget).join(",")).toBe("$:/TiddlerTwo,Tiddler Three,TiddlerOne,a fourth tiddler");
|
expect(wiki.filterTiddlers("[[TiddlerOne]] [[$:/TiddlerTwo]] [[Tiddler Three]] [[a fourth tiddler]] +[!sortsub:number<sort3>]",anchorWidget).join(",")).toBe("$:/TiddlerTwo,Tiddler Three,TiddlerOne,a fourth tiddler");
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue
Block a user