Named filter run prefixes (#4915)

* First pass at refactoring filter code to support named filter run prefixes

* Remove filter prefix for now

* renamed module type and filter run prefixes

* Moved inline handling for no filter run prefix to 'or' filter run prefix.

* Added error handling for undefined filter run prefixes
optimising-macrocalls
saqimtiaz 2020-10-27 13:24:18 +01:00 zatwierdzone przez GitHub
rodzic 3843c61132
commit c9efa23f02
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
7 zmienionych plików z 161 dodań i 26 usunięć

Wyświetl plik

@ -26,6 +26,7 @@ Error/Caption: Error
Error/EditConflict: File changed on server
Error/Filter: Filter error
Error/FilterSyntax: Syntax error in filter expression
Error/FilterRunPrefix: Filter Error: Unknown prefix for filter run
Error/IsFilterOperator: Filter Error: Unknown operand for the 'is' filter operator
Error/FormatFilterOperator: Filter Error: Unknown suffix for the 'format' filter operator
Error/LoadingPluginLibrary: Error loading plugin library

Wyświetl plik

@ -0,0 +1,25 @@
/*\
title: $:/core/modules/filterrunprefixes/all.js
type: application/javascript
module-type: filterrunprefix
Union of sets without de-duplication.
Equivalent to = filter run prefix.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter prefix function
*/
exports.all = function(operationSubFunction) {
return function(results,source,widget) {
Array.prototype.push.apply(results,operationSubFunction(source,widget));
};
};
})();

Wyświetl plik

@ -0,0 +1,28 @@
/*\
title: $:/core/modules/filterrunprefixes/and.js
type: application/javascript
module-type: filterrunprefix
Intersection of sets.
Equivalent to + filter run prefix.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter prefix function
*/
exports.and = function(operationSubFunction) {
return function(results,source,widget) {
// This replaces all the elements of the array, but keeps the actual array so that references to it are preserved
source = $tw.wiki.makeTiddlerIterator(results);
results.splice(0,results.length);
$tw.utils.pushTop(results,operationSubFunction(source,widget));
};
};
})();

Wyświetl plik

@ -0,0 +1,27 @@
/*\
title: $:/core/modules/filterrunprefixes/else.js
type: application/javascript
module-type: filterrunprefix
Equivalent to ~ filter run prefix.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter prefix function
*/
exports.else = function(operationSubFunction) {
return function(results,source,widget) {
if(results.length === 0) {
// Main result so far is empty
$tw.utils.pushTop(results,operationSubFunction(source,widget));
}
};
};
})();

Wyświetl plik

@ -0,0 +1,25 @@
/*\
title: $:/core/modules/filterrunprefixes/except.js
type: application/javascript
module-type: filterrunprefix
Difference of sets.
Equivalent to - filter run prefix.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter prefix function
*/
exports.except = function(operationSubFunction) {
return function(results,source,widget) {
$tw.utils.removeArrayEntries(results,operationSubFunction(source,widget));
};
};
})();

Wyświetl plik

@ -0,0 +1,24 @@
/*\
title: $:/core/modules/filterrunprefixes/or.js
type: application/javascript
module-type: filterrunprefix
Equivalent to a filter run with no prefix.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter prefix function
*/
exports.or = function(operationSubFunction) {
return function(results,source,widget) {
$tw.utils.pushTop(results,operationSubFunction(source,widget));
};
};
})();

Wyświetl plik

@ -119,7 +119,7 @@ exports.parseFilter = function(filterString) {
p = 0, // Current position in the filter string
match;
var whitespaceRegExp = /(\s+)/mg,
operandRegExp = /((?:\+|\-|~|=)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
operandRegExp = /((?:\+|\-|~|=|\:(\w+))?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
while(p < filterString.length) {
// Skip any whitespace
whitespaceRegExp.lastIndex = p;
@ -140,16 +140,19 @@ exports.parseFilter = function(filterString) {
};
if(match[1]) {
operation.prefix = match[1];
p++;
p = p + operation.prefix.length;
if(match[2]) {
operation.namedPrefix = match[2];
}
}
if(match[2]) { // Opening square bracket
if(match[3]) { // Opening square bracket
p = parseFilterOperation(operation.operators,filterString,p);
} else {
p = match.index + match[0].length;
}
if(match[3] || match[4] || match[5]) { // 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(
{operator: "title", operand: match[3] || match[4] || match[5]}
{operator: "title", operand: match[4] || match[5] || match[6]}
);
}
results.push(operation);
@ -166,6 +169,14 @@ exports.getFilterOperators = function() {
return this.filterOperators;
};
exports.getFilterRunPrefixes = function() {
if(!this.filterPrefixes) {
$tw.Wiki.prototype.filterRunPrefixes = {};
$tw.modules.applyMethods("filterrunprefix",this.filterRunPrefixes);
}
return this.filterRunPrefixes;
}
exports.filterTiddlers = function(filterString,widget,source) {
var fn = this.compileFilter(filterString);
return fn.call(this,source,widget);
@ -241,35 +252,29 @@ exports.compileFilter = function(filterString) {
return resultArray;
}
};
var filterRunPrefixes = self.getFilterRunPrefixes();
// Wrap the operator functions in a wrapper function that depends on the prefix
operationFunctions.push((function() {
switch(operation.prefix || "") {
case "": // No prefix means that the operation is unioned into the result
return function(results,source,widget) {
$tw.utils.pushTop(results,operationSubFunction(source,widget));
};
return filterRunPrefixes["or"](operationSubFunction);
case "=": // The results of the operation are pushed into the result without deduplication
return function(results,source,widget) {
Array.prototype.push.apply(results,operationSubFunction(source,widget));
};
return filterRunPrefixes["all"](operationSubFunction);
case "-": // The results of this operation are removed from the main result
return function(results,source,widget) {
$tw.utils.removeArrayEntries(results,operationSubFunction(source,widget));
};
return filterRunPrefixes["except"](operationSubFunction);
case "+": // This operation is applied to the main results so far
return function(results,source,widget) {
// This replaces all the elements of the array, but keeps the actual array so that references to it are preserved
source = self.makeTiddlerIterator(results);
results.splice(0,results.length);
$tw.utils.pushTop(results,operationSubFunction(source,widget));
};
return filterRunPrefixes["and"](operationSubFunction);
case "~": // This operation is unioned into the result only if the main result so far is empty
return function(results,source,widget) {
if(results.length === 0) {
// Main result so far is empty
$tw.utils.pushTop(results,operationSubFunction(source,widget));
}
};
return filterRunPrefixes["else"](operationSubFunction);
default:
if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) {
return filterRunPrefixes[operation.namedPrefix](operationSubFunction);
} else {
return function(results,source,widget) {
results.splice(0,results.length);
results.push($tw.language.getString("Error/FilterRunPrefix"));
};
}
}
})());
});