From 45d2ca948a951059d9f7aeb4e0481152787a8951 Mon Sep 17 00:00:00 2001 From: Saq Imtiaz Date: Tue, 28 Jul 2026 12:32:48 +0200 Subject: [PATCH] Optimizes filterrunprefixes & filters using ES2017 (#9943) * refactor: use ES2017 to optimize filter run prefixes * chore: eslint * chore: eslint * fix: added missing file * refactor: prefix, suffix and subfilter operators * refactor: further improvements using new String methods * docs: added changenote * chore: renamed docs tiddler * chore: renamed docs tiddler --- .../modules/filterrunprefixes/intersection.js | 11 +++-- core/modules/filterrunprefixes/sort.js | 35 ++++++-------- core/modules/filters/prefix.js | 7 ++- core/modules/filters/sortsub.js | 19 +++----- core/modules/filters/subfilter.js | 9 ++-- core/modules/filters/suffix.js | 48 +++++++------------ .../tiddlers/releasenotes/5.5.0/#9943.tid | 13 +++++ 7 files changed, 66 insertions(+), 76 deletions(-) create mode 100644 editions/tw5.com/tiddlers/releasenotes/5.5.0/#9943.tid diff --git a/core/modules/filterrunprefixes/intersection.js b/core/modules/filterrunprefixes/intersection.js index ce9ea45463..02329d7b95 100644 --- a/core/modules/filterrunprefixes/intersection.js +++ b/core/modules/filterrunprefixes/intersection.js @@ -13,14 +13,15 @@ Export our filter prefix function exports.intersection = function(operationSubFunction) { return function(results,source,widget) { if(results.length !== 0) { - var secondRunResults = operationSubFunction(source,widget); - var firstRunResults = results.toArray(); + const secondRunResults = operationSubFunction(source,widget), + secondRunSet = new Set(secondRunResults), + firstRunResults = results.toArray(); results.clear(); - $tw.utils.each(firstRunResults,function(title) { - if(secondRunResults.indexOf(title) !== -1) { + firstRunResults.forEach((title) => { + if(secondRunSet.has(title)) { results.push(title); } }); } }; -}; +}; \ No newline at end of file diff --git a/core/modules/filterrunprefixes/sort.js b/core/modules/filterrunprefixes/sort.js index 41d017832f..1a8a647854 100644 --- a/core/modules/filterrunprefixes/sort.js +++ b/core/modules/filterrunprefixes/sort.js @@ -13,33 +13,28 @@ Export our filter prefix function exports.sort = function(operationSubFunction,options) { return function(results,source,widget) { if(results.length > 0) { - var suffixes = options.suffixes, + const suffixes = options.suffixes, sortType = (suffixes[0] && suffixes[0][0]) ? suffixes[0][0] : "string", - invert = suffixes[1] ? (suffixes[1].indexOf("reverse") !== -1) : false, - isCaseSensitive = suffixes[1] ? (suffixes[1].indexOf("casesensitive") !== -1) : false, + invert = suffixes[1] ? suffixes[1].includes("reverse") : false, + isCaseSensitive = suffixes[1] ? suffixes[1].includes("casesensitive") : false, inputTitles = results.toArray(), sortKeys = [], - indexes = new Array(inputTitles.length), - compareFn; - results.each(function(title) { - var key = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({ - "currentTiddler": "" + title, - "..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""}) - })); + compareFn = $tw.utils.makeCompareFunction(sortType,{defaultType: "string", invert:invert, isCaseSensitive:isCaseSensitive}); + results.each((title) => { + const key = operationSubFunction( + options.wiki.makeTiddlerIterator([title]), + widget.makeFakeWidgetWithVariables({ + "currentTiddler": "" + title, + "..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""}) + }) + ); sortKeys.push(key[0] || ""); }); results.clear(); // Prepare an array of indexes to sort - for(var t=0; t compareFn(sortKeys[a],sortKeys[b])); + indexes.forEach((index) => { results.push(inputTitles[index]); }); } diff --git a/core/modules/filters/prefix.js b/core/modules/filters/prefix.js index fb8b2aca7f..803726a6d8 100644 --- a/core/modules/filters/prefix.js +++ b/core/modules/filters/prefix.js @@ -15,7 +15,7 @@ Export our filter function exports.prefix = function(source,operator,options) { const results = [], suffixes = (operator.suffixes || [])[0] || [], - caseInsensitive = suffixes.indexOf("caseinsensitive") !== -1, + caseInsensitive = suffixes.includes("caseinsensitive"), negate = operator.prefix === "!"; const operand = caseInsensitive ? @@ -23,9 +23,8 @@ exports.prefix = function(source,operator,options) { operator.operand; source((tiddler,title) => { - const value = caseInsensitive ? title.toLowerCase() : title; - const matches = value.startsWith(operand); - + const value = caseInsensitive ? title.toLowerCase() : title, + matches = value.startsWith(operand); if(negate ? !matches : matches) { results.push(title); } diff --git a/core/modules/filters/sortsub.js b/core/modules/filters/sortsub.js index 291829992a..4e88c11f3f 100644 --- a/core/modules/filters/sortsub.js +++ b/core/modules/filters/sortsub.js @@ -14,13 +14,13 @@ Export our filter function */ exports.sortsub = function(source,operator,options) { // Compile the subfilter - var filterFn = options.wiki.compileFilter(operator.operand); + let filterFn = options.wiki.compileFilter(operator.operand); // Collect the input titles and the corresponding sort keys - var inputTitles = [], + let inputTitles = [], sortKeys = []; source(function(tiddler,title) { inputTitles.push(title); - var r = filterFn.call(options.wiki,function(iterator) { + let r = filterFn.call(options.wiki,function(iterator) { iterator(options.wiki.getTiddler(title),title); },options.widget.makeFakeWidgetWithVariables({ "currentTiddler": "" + title, @@ -29,17 +29,12 @@ exports.sortsub = function(source,operator,options) { sortKeys.push(r[0] || ""); }); // Rather than sorting the titles array, we'll sort the indexes so that we can consult both arrays - var indexes = new Array(inputTitles.length); - for(var t=0; t compareFn(sortKeys[a],sortKeys[b])); // Make the results array in order - var results = []; + let results = []; $tw.utils.each(indexes,function(index) { results.push(inputTitles[index]); }); diff --git a/core/modules/filters/subfilter.js b/core/modules/filters/subfilter.js index 5e35f7cd17..abec0addd3 100644 --- a/core/modules/filters/subfilter.js +++ b/core/modules/filters/subfilter.js @@ -13,11 +13,12 @@ Filter operator returning its operand evaluated as a filter Export our filter function */ exports.subfilter = function(source,operator,options) { - var list = options.wiki.filterTiddlers(operator.operand,options.widget,source); + const list = options.wiki.filterTiddlers(operator.operand,options.widget,source); if(operator.prefix === "!") { - var results = []; - source(function(tiddler,title) { - if(list.indexOf(title) === -1) { + const results = [], + listSet = new Set(list); + source((tiddler,title) => { + if(!listSet.has(title)) { results.push(title); } }); diff --git a/core/modules/filters/suffix.js b/core/modules/filters/suffix.js index 74e7ecd143..31e505d1b7 100644 --- a/core/modules/filters/suffix.js +++ b/core/modules/filters/suffix.js @@ -13,41 +13,27 @@ Filter operator for checking if a title ends with a suffix Export our filter function */ exports.suffix = function(source,operator,options) { - var results = [], + const results = [], suffixes = (operator.suffixes || [])[0] || []; + if(!operator.operand) { - source(function(tiddler,title) { + source((tiddler,title) => { results.push(title); }); - } else if(suffixes.indexOf("caseinsensitive") !== -1) { - var operand = operator.operand.toLowerCase(); - if(operator.prefix === "!") { - source(function(tiddler,title) { - if(title.toLowerCase().substr(-operand.length) !== operand) { - results.push(title); - } - }); - } else { - source(function(tiddler,title) { - if(title.toLowerCase().substr(-operand.length) === operand) { - results.push(title); - } - }); - } - } else { - if(operator.prefix === "!") { - source(function(tiddler,title) { - if(title.substr(-operator.operand.length) !== operator.operand) { - results.push(title); - } - }); - } else { - source(function(tiddler,title) { - if(title.substr(-operator.operand.length) === operator.operand) { - results.push(title); - } - }); - } + return results; } + + const caseInsensitive = suffixes.indexOf("caseinsensitive") !== -1, + negate = operator.prefix === "!", + operand = caseInsensitive ? operator.operand.toLowerCase() : operator.operand; + + source((tiddler,title) => { + const value = caseInsensitive ? title.toLowerCase() : title, + matches = value.endsWith(operand); + if(negate ? !matches : matches) { + results.push(title); + } + }); + return results; }; diff --git a/editions/tw5.com/tiddlers/releasenotes/5.5.0/#9943.tid b/editions/tw5.com/tiddlers/releasenotes/5.5.0/#9943.tid new file mode 100644 index 0000000000..fb8a4c1723 --- /dev/null +++ b/editions/tw5.com/tiddlers/releasenotes/5.5.0/#9943.tid @@ -0,0 +1,13 @@ +change-category: filters +change-type: enhancement +created: 20260726124618748 +description: Optimizes filterrun prefixes and select filters using modern JavaScript. +github-contributors: saqimtiaz +github-links: https://github.com/TiddlyWiki/TiddlyWiki5/issues/9943 +modified: 20260726130207664 +release: 5.5.0 +tags: $:/tags/ChangeNote +title: $:/changenotes/5.5.0/#9943 +type: text/vnd.tiddlywiki + +* The `intersection` and `sort` filterrun prefixes, and the `prefix`, `sortsub`, `subfilter` and `suffix` operators have been optimized using more modern JavaScript (ES2017). \ No newline at end of file