mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-01-02 21:49:04 +00:00
Add remote inspection of preconfigured filters
There is no user interface yet, and it is currently hardcoded to inspect the filter "[all[shadows+tiddlers]tag[$:/tags/ViewTemplate]!is[draft]]" which is used in tiddler rendering. You can see the results in the sidebar More -> System starting with "$:/temp/filter-inspection/"
This commit is contained in:
@@ -2732,14 +2732,15 @@ $tw.hooks.removeHook = function(hookName,definition) {
|
||||
/*
|
||||
Invoke the hook by key
|
||||
*/
|
||||
$tw.hooks.invokeHook = function(hookName /*, value,... */) {
|
||||
var args = Array.prototype.slice.call(arguments,1);
|
||||
if($tw.utils.hop($tw.hooks.names,hookName)) {
|
||||
$tw.hooks.invokeHook = function(hookName, firstArgument /*, value,... */) {
|
||||
if(Object.prototype.hasOwnProperty.call($tw.hooks.names,hookName)) {
|
||||
var args = Array.prototype.slice.call(arguments,1);
|
||||
for(var i = 0; i < $tw.hooks.names[hookName].length; i++) {
|
||||
args[0] = $tw.hooks.names[hookName][i].apply(null,args);
|
||||
}
|
||||
return args[0];
|
||||
}
|
||||
return args[0];
|
||||
return firstArgument;
|
||||
};
|
||||
|
||||
/////////////////////////// Main boot function to decrypt tiddlers and then startup
|
||||
|
||||
@@ -231,11 +231,14 @@ exports.compileFilter = function(filterString,options) {
|
||||
options = options || {};
|
||||
var self = this;
|
||||
var wrappers = options.wrappers || {};
|
||||
// Invoke the hook to allow the filter to be inspected
|
||||
wrappers = $tw.hooks.invokeHook("th-filter-evaluation",filterString,wrappers) || wrappers;
|
||||
// Get the result from the cache if we can
|
||||
if(!this.filterCache) {
|
||||
this.filterCache = Object.create(null);
|
||||
this.filterCacheCount = 0;
|
||||
}
|
||||
if(this.filterCache[filterString] !== undefined && !wrappers.prefix && !wrappers.operation && !wrappers.operator) {
|
||||
if(this.filterCache[filterString] !== undefined && !wrappers.prefix && !wrappers.operation && !wrappers.operator && !wrappers.start && !wrappers.done) {
|
||||
return this.filterCache[filterString];
|
||||
}
|
||||
var filterParseTree;
|
||||
@@ -379,6 +382,9 @@ exports.compileFilter = function(filterString,options) {
|
||||
if(!widget) {
|
||||
widget = $tw.rootWidget;
|
||||
}
|
||||
if(wrappers.start) {
|
||||
wrappers.start(source);
|
||||
}
|
||||
var results = new $tw.utils.LinkedList();
|
||||
self.filterRecursionCount = (self.filterRecursionCount || 0) + 1;
|
||||
if(self.filterRecursionCount < MAX_FILTER_DEPTH) {
|
||||
@@ -389,7 +395,11 @@ exports.compileFilter = function(filterString,options) {
|
||||
results.push("/**-- Excessive filter recursion --**/");
|
||||
}
|
||||
self.filterRecursionCount = self.filterRecursionCount - 1;
|
||||
return results.toArray();
|
||||
var resultsArray = results.toArray();
|
||||
if(wrappers.done) {
|
||||
wrappers.done(resultsArray);
|
||||
}
|
||||
return resultsArray;
|
||||
});
|
||||
if(this.filterCacheCount >= 2000) {
|
||||
// To prevent memory leak, we maintain an upper limit for cache size.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
title: $:/plugins/internals/cascades/viewtemplatebody
|
||||
tags: $:/tags/ViewTemplateBodyFilter
|
||||
list-before:
|
||||
|
||||
[tag[$:/tags/FilterInspectionOutput]type[application/json]then[$:/plugins/internals/templates/viewtemplatebody]]
|
||||
@@ -141,26 +141,28 @@ tags: $:/tags/Macro
|
||||
</div>
|
||||
\end inspect-run
|
||||
|
||||
\procedure inspect-filter(filter,inputFilter:"[all[tiddlers]]",orientation:"horizontal")
|
||||
<$let json={{{ [subfilter<inputFilter>inspect<filter>] }}}>
|
||||
<$scrollable bind={{{ [<qualify "$:/temp/filter-inspector/">addsuffix<filter>] }}}>
|
||||
<div class={{{ tc-inspect-filter-box [<orientation>match[horizontal]then[tc-inspect-filter-box-horizontal]] +[join[ ]] }}}>
|
||||
<div class="tc-box">
|
||||
<div class="tc-box-header">
|
||||
Filter
|
||||
<span class="tc-pill"><$text text={{{ [<json>jsonget[inputFilter]] }}}/></span>
|
||||
</div>
|
||||
<div class="tc-box-content">
|
||||
<$transclude $variable="inspect-list" jsonList={{{ [<json>jsonextract[input]] }}} class="tc-box tc-inspect-input-box"/>
|
||||
<$list filter="[<json>jsonindexes[runs]nsort[]]" variable="indexRun">
|
||||
<$let transclusion={{{ [[run-]addsuffix<indexRun>] }}}>
|
||||
<$transclude $variable="inspect-run" jsonRun={{{ [<json>jsonextract[runs],<indexRun>] }}}/>
|
||||
</$let>
|
||||
</$list>
|
||||
<$transclude $variable="inspect-list" jsonList={{{ [<json>jsonextract[output]] }}} class="tc-box tc-inspect-output-box"/>
|
||||
</div>
|
||||
\procedure inspect-filter-output(jsonOutput,orientation:"horizontal")
|
||||
<$scrollable bind={{{ [<qualify "$:/temp/filter-inspector/">addsuffix<filter>] }}}>
|
||||
<div class={{{ tc-inspect-filter-box [<orientation>match[horizontal]then[tc-inspect-filter-box-horizontal]] +[join[ ]] }}}>
|
||||
<div class="tc-box">
|
||||
<div class="tc-box-header">
|
||||
Filter
|
||||
<span class="tc-pill"><$text text={{{ [<jsonOutput>jsonget[inputFilter]] }}}/></span>
|
||||
</div>
|
||||
<div class="tc-box-content">
|
||||
<$transclude $variable="inspect-list" jsonList={{{ [<jsonOutput>jsonextract[input]] }}} class="tc-box tc-inspect-input-box"/>
|
||||
<$list filter="[<jsonOutput>jsonindexes[runs]nsort[]]" variable="indexRun">
|
||||
<$let transclusion={{{ [[run-]addsuffix<indexRun>] }}}>
|
||||
<$transclude $variable="inspect-run" jsonRun={{{ [<jsonOutput>jsonextract[runs],<indexRun>] }}}/>
|
||||
</$let>
|
||||
</$list>
|
||||
<$transclude $variable="inspect-list" jsonList={{{ [<jsonOutput>jsonextract[output]] }}} class="tc-box tc-inspect-output-box"/>
|
||||
</div>
|
||||
</div>
|
||||
</$scrollable>
|
||||
</$let>
|
||||
</div>
|
||||
</$scrollable>
|
||||
\end inspect-filter-output
|
||||
|
||||
\procedure inspect-filter(filter,inputFilter:"[all[tiddlers]]",orientation:"horizontal")
|
||||
<$transclude $variable="inspect-filter-output" jsonOutput={{{ [subfilter<inputFilter>inspect<filter>] }}} orientation=<<orientation>> />
|
||||
\end inspect-filter
|
||||
|
||||
@@ -9,79 +9,21 @@ Filter operator for inspecting the evaluation of a filter
|
||||
|
||||
"use strict";
|
||||
|
||||
var getWrappers = $tw.plugins.internals.getWrappers;
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.inspect = function(source,operator,options) {
|
||||
var self = this,
|
||||
inputFilter = operator.operands[0] || "",
|
||||
output = {
|
||||
input: [],
|
||||
runs: [],
|
||||
inputFilter: inputFilter
|
||||
},
|
||||
currentRun,currentOperation;
|
||||
// Save the input
|
||||
source(function(tiddler,title) {
|
||||
output.input.push(title);
|
||||
});
|
||||
var inputFilter = operator.operands[0] || "",
|
||||
results,
|
||||
wrappers = getWrappers(function(output) {
|
||||
results = output;
|
||||
},inputFilter);
|
||||
// Compile the filter with wrapper functions to log the details
|
||||
var compiledFilter = options.wiki.compileFilter(inputFilter,{
|
||||
wrappers: {
|
||||
prefix: function(filterRunPrefixFunction,operationFunction,innerOptions) {
|
||||
return function(results,innerSource,innerWidget) {
|
||||
var details ={
|
||||
input: results.toArray(),
|
||||
prefixName: innerOptions.prefixName,
|
||||
suffixes: innerOptions.suffixes,
|
||||
operations: []
|
||||
};
|
||||
currentRun = details.operations;
|
||||
var innerResults = filterRunPrefixFunction.call(null,operationFunction,innerOptions);
|
||||
innerResults(results,innerSource,innerWidget);
|
||||
details.output = results.toArray();
|
||||
output.runs.push(details);
|
||||
};
|
||||
},
|
||||
operation: function(operationFunction,operation) {
|
||||
var details = {
|
||||
operators: []
|
||||
}
|
||||
currentOperation = details.operators;
|
||||
currentRun.push(details);
|
||||
operationFunction();
|
||||
},
|
||||
operator: function(operatorFunction,innerSource,innerOperator,innerOptions) {
|
||||
var details = {
|
||||
operatorName: innerOperator.operatorName,
|
||||
operands: innerOperator.operands,
|
||||
parseTree: innerOperator.parseTree,
|
||||
prefix: innerOperator.prefix,
|
||||
suffix: innerOperator.suffix,
|
||||
suffixes: innerOperator.suffixes,
|
||||
regexp: innerOperator.regexp,
|
||||
input: []
|
||||
};
|
||||
innerSource(function(tiddler,title) {
|
||||
details.input.push(title);
|
||||
});
|
||||
currentOperation.push(details);
|
||||
var innerResults = operatorFunction.apply(null,Array.prototype.slice.call(arguments,1));
|
||||
if(!$tw.utils.isArray(innerResults)) {
|
||||
var resultArray = [];
|
||||
innerResults(function(tiddler,title) {
|
||||
resultArray.push(title);
|
||||
});
|
||||
innerResults = resultArray;
|
||||
}
|
||||
details.output = innerResults;
|
||||
return innerResults;
|
||||
}
|
||||
}
|
||||
wrappers: wrappers
|
||||
});
|
||||
output.output = compiledFilter.call(options.wiki,source,options.widget);
|
||||
var results = [];
|
||||
// console.log(`Inspected ${JSON.stringify(output,null,4)}`);
|
||||
results.push(JSON.stringify(output,null,4));
|
||||
return results;
|
||||
};
|
||||
compiledFilter.call(options.wiki,source,options.widget);
|
||||
return [JSON.stringify(results)];
|
||||
};
|
||||
158
plugins/tiddlywiki/internals/modules/startup.js
Normal file
158
plugins/tiddlywiki/internals/modules/startup.js
Normal file
@@ -0,0 +1,158 @@
|
||||
/*\
|
||||
title: $:/plugins/tiddlywiki/internals/startup.js
|
||||
type: application/javascript
|
||||
module-type: startup
|
||||
|
||||
Install hooks
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// Export name and synchronous status
|
||||
exports.name = "internals-plugin";
|
||||
exports.before = ["startup"];
|
||||
exports.synchronous = true;
|
||||
|
||||
exports.startup = function() {
|
||||
$tw.plugins = $tw.plugins || {};
|
||||
$tw.plugins.internals = {
|
||||
getWrappers: getWrappers
|
||||
};
|
||||
var inspectedFilters = [
|
||||
"[all[shadows+tiddlers]tag[$:/tags/ViewTemplate]!is[draft]]"
|
||||
],
|
||||
accumulator = [];
|
||||
$tw.hooks.addHook("th-filter-evaluation",function(filterString,wrappers) {
|
||||
// Check whether this is a filter we want to inspect
|
||||
if(inspectedFilters.indexOf(filterString) === -1) {
|
||||
return wrappers;
|
||||
}
|
||||
// Don't do anything if there are already wrappers
|
||||
if(wrappers.prefix || wrappers.operation || wrappers.operator) {
|
||||
return wrappers;
|
||||
}
|
||||
var flushAccumulator = function() {
|
||||
if(accumulator.length) {
|
||||
$tw.utils.each(accumulator,function(jsonInspectionOutput) {
|
||||
// Get the output as a string
|
||||
var stringInspectionOutput = JSON.stringify(jsonInspectionOutput),
|
||||
logPrefix = `$:/temp/filter-inspection/${ + $tw.utils.stringifyDate(new Date())}: `,
|
||||
logPrefixLength = logPrefix.length;
|
||||
// Check if the the output is the same as the last log with the same filter
|
||||
var logTitles = [];
|
||||
$tw.wiki.each(function(tiddler,title) {
|
||||
if(title.substring(logPrefixLength) === filterString) {
|
||||
logTitles.push(title);
|
||||
}
|
||||
});
|
||||
var alreadyLogged = false;
|
||||
$tw.utils.each(logTitles,function(title) {
|
||||
var jsonLog = $tw.wiki.getTiddlerData(title);
|
||||
if($tw.utils.isArrayEqual(jsonLog.output,jsonInspectionOutput.output)) {
|
||||
alreadyLogged = true;
|
||||
}
|
||||
});
|
||||
if(alreadyLogged) {
|
||||
return;
|
||||
}
|
||||
// Add the log tiddler
|
||||
var tiddlerFields = {
|
||||
title: `${logPrefix}${filterString}`,
|
||||
tags: ["$:/tags/FilterInspectionOutput"],
|
||||
text: stringInspectionOutput,
|
||||
filter: filterString,
|
||||
type: "application/json"
|
||||
}
|
||||
// console.log("Adding " + JSON.stringify(tiddlerFields));
|
||||
$tw.wiki.addTiddler(new $tw.Tiddler($tw.wiki.getCreationFields(),$tw.wiki.getModificationFields(),tiddlerFields));
|
||||
});
|
||||
accumulator = [];
|
||||
}
|
||||
};
|
||||
// Get our wrappers
|
||||
return getWrappers(function(output) {
|
||||
// Schedule a flush
|
||||
if(accumulator.length === 0) {
|
||||
$tw.utils.nextTick(function() {
|
||||
flushAccumulator();
|
||||
});
|
||||
}
|
||||
accumulator.push(output);
|
||||
},filterString);
|
||||
});
|
||||
};
|
||||
|
||||
function getWrappers(fnDone,inputFilter) {
|
||||
var output = {
|
||||
inputFilter: inputFilter,
|
||||
input: [],
|
||||
runs: []
|
||||
},
|
||||
currentRun,currentOperation;
|
||||
// Compile the filter with wrapper functions to log the details
|
||||
return {
|
||||
start: function(source) {
|
||||
// Save the input
|
||||
source(function(tiddler,title) {
|
||||
output.input.push(title);
|
||||
});
|
||||
},
|
||||
prefix: function(filterRunPrefixFunction,operationFunction,innerOptions) {
|
||||
return function(results,innerSource,innerWidget) {
|
||||
var details ={
|
||||
input: results.toArray(),
|
||||
prefixName: innerOptions.prefixName,
|
||||
suffixes: innerOptions.suffixes,
|
||||
operations: []
|
||||
};
|
||||
currentRun = details.operations;
|
||||
var innerResults = filterRunPrefixFunction.call(null,operationFunction,innerOptions);
|
||||
innerResults(results,innerSource,innerWidget);
|
||||
details.output = results.toArray();
|
||||
output.runs.push(details);
|
||||
};
|
||||
},
|
||||
operation: function(operationFunction,operation) {
|
||||
var details = {
|
||||
operators: []
|
||||
}
|
||||
currentOperation = details.operators;
|
||||
currentRun.push(details);
|
||||
operationFunction();
|
||||
},
|
||||
operator: function(operatorFunction,innerSource,innerOperator,innerOptions) {
|
||||
var details = {
|
||||
operatorName: innerOperator.operatorName,
|
||||
operands: innerOperator.operands,
|
||||
parseTree: innerOperator.parseTree,
|
||||
prefix: innerOperator.prefix,
|
||||
suffix: innerOperator.suffix,
|
||||
suffixes: innerOperator.suffixes,
|
||||
regexp: innerOperator.regexp,
|
||||
input: []
|
||||
};
|
||||
innerSource(function(tiddler,title) {
|
||||
details.input.push(title);
|
||||
});
|
||||
currentOperation.push(details);
|
||||
var innerResults = operatorFunction.apply(null,Array.prototype.slice.call(arguments,1));
|
||||
if(!$tw.utils.isArray(innerResults)) {
|
||||
var resultArray = [];
|
||||
innerResults(function(tiddler,title) {
|
||||
resultArray.push(title);
|
||||
});
|
||||
innerResults = resultArray;
|
||||
}
|
||||
details.output = innerResults;
|
||||
return innerResults;
|
||||
},
|
||||
done: function(results) {
|
||||
output.output = results;
|
||||
// console.log(`Inspected ${JSON.stringify(output,null,4)}`);
|
||||
if(fnDone) {
|
||||
fnDone(output);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
title: $:/plugins/internals/templates/viewtemplatebody
|
||||
|
||||
<$transclude $variable="inspect-filter-output" jsonOutput={{!!text}} />
|
||||
Reference in New Issue
Block a user