filters mostly working...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2026-07-09 17:10:50 +03:00
parent fa720d40fd
commit 71a4b7f41b

View File

@ -270,13 +270,19 @@ module.BaseParser = {
: []), : []),
] }) ] })
.flat() }, .flat() },
filterBlocks: function(page, blocks, filter, state){
if(filter == null){
return blocks }
// XXX applyFilters: function(filters, str, state={}){
var that = this
return blocks }, filters = this.normalizeFilters(filters)
.filter(function(f){
return f in (that.filters ?? {})})
var handle = function(str){
return filters
.reduce(function(res, filter){
return that.filters[filter].call(that, str, state) }, str) }
return str instanceof Array ?
str.map(handle)
: handle(str) },
// Strip comments... // Strip comments...
@ -600,7 +606,6 @@ module.BaseParser = {
// states and the like, async/await can't... // states and the like, async/await can't...
// XXX Q: do we need generators? // XXX Q: do we need generators?
// XXX Handle errors... // XXX Handle errors...
fullAST: true,
// XXX this needs a careful rewrite of the .macros.* for the new scheme: // XXX this needs a careful rewrite of the .macros.* for the new scheme:
// - expand // - expand
// - "merge" // - "merge"
@ -687,6 +692,8 @@ module.BaseParser = {
delete state.waitNested } delete state.waitNested }
delete elem.resolving delete elem.resolving
elem.value = value elem.value = value
// XXX should we resolve to value or elem???
// ...elem seems more consistent...
return value }, return value },
function(err){ function(err){
state.errors ??= [] state.errors ??= []
@ -694,14 +701,8 @@ module.BaseParser = {
delete elem.resolving delete elem.resolving
elem.error = err }) elem.error = err })
// sync... // sync...
} else if('fullAST' in state ?
state.fullAST
: 'fullAST' in page ?
page.fullAST
: this.fullAST){
elem.value = res
} else { } else {
elem = res } elem.value = res }
elems.push(elem) } elems.push(elem) }
// cleanup... // cleanup...
@ -814,8 +815,20 @@ module.BaseParser = {
// XXX // XXX
}, },
exec: function(page, ast, state={}, nested_handlers={}, wait='wait'){ // merge stage III...
//
// XXX FILTER should filters he handled here or in .resolve(..) ???
// ...and how do we handle filters in @include(..)'s???
merge: function(page, ast, state={}, nested_handlers={}, wait='wait'){
var that = this var that = this
var stage3 = function(ast){
return ast
.map(function(e){
return typeof(e) == 'function' ?
e.call(that, state)
: e })
.flat() }
// XXX might be a good idea to limit recursion depth here... // XXX might be a good idea to limit recursion depth here...
var merge = function(ast){ var merge = function(ast){
return Promise.awaitOrRun( return Promise.awaitOrRun(
@ -823,7 +836,8 @@ module.BaseParser = {
function(){ function(){
delete state.unresolved delete state.unresolved
// re-resolve... // re-resolve...
ast = that.resolve(page, ast, state, nested_handlers) ast = stage3(
that.resolve(page, ast, state, nested_handlers))
// NOTE: this is essentially running in the same frame // NOTE: this is essentially running in the same frame
// as .resolve(..) above so there should not be // as .resolve(..) above so there should not be
@ -832,17 +846,26 @@ module.BaseParser = {
merge(ast) merge(ast)
: (ast ?? '').join('') }) } : (ast ?? '').join('') }) }
ast = stage3(
this.resolve(page, ast, state, nested_handlers))
return Promise.awaitOrRun( return Promise.awaitOrRun(
this.resolve(page, ast, state, nested_handlers),
state[wait], state[wait],
function(ast){ function(){
//ast = stage3(ast)
// NOTE: in an async world where any promised macro can // NOTE: in an async world where any promised macro can
// call .exec(..) / .execNested(..) we can't trust // call .exec(..) / .execNested(..) we can't trust
// the lack of .unresolved in state... // the lack of .unresolved in state...
return (state.unresolved return that.applyFilters(
|| !that.isResolved(ast)) ? state.filters ?? [],
merge(ast) (state.unresolved
: (ast ?? '').join('') }) }, || !that.isResolved(ast)) ?
merge(ast)
: (ast ?? '').join(''),
state) }) },
exec: function(page, ast, state={}, nested_handlers={}, wait='wait'){
return this.merge(...arguments) },
// XXX how should this play with filters??? // XXX how should this play with filters???
@ -900,6 +923,12 @@ module.parser = {
INCLUDE_NEST_LIMIT: 20, INCLUDE_NEST_LIMIT: 20,
// XXX should this be here, in page, or both?
filters: {
upper: function(str){
return str.toUpperCase() },
},
// //
// <macro>(<args>, <body>, <state>){ .. } // <macro>(<args>, <body>, <state>){ .. }
// -> undefined // -> undefined
@ -926,74 +955,39 @@ module.parser = {
// <filter> <filter-spec> // <filter> <filter-spec>
// | -<filter> <filter-spec> // | -<filter> <filter-spec>
// //
// XXX the rewrite: // XXX need a way to exclude some filters in some nested locks...
// - these need to be called after everything is done // XXX BUG: RECURSION: this breaks @include(..)'s recursion tests...
// - globally in .exec(..) ??? filter: function(page, args, body, state){
// - localy after the item content is ready
// -> should we have and .onDone(..) event somwhere in the tree???
// ...this would be usefull for the callback renderer too...
//
// XXX BUG: this does not show any results:
// pwiki.exec('<filter test>moo test</filter>')
// -> ''
// while these do:
// pwiki.exec('<filter test/>moo test')
// -> 'moo TEST'
// await pwiki.exec('<filter test>moo test</filter>@var()')
// -> 'moo TEST'
// for more info see:
// file:///L:/work/pWiki/pwiki2.html#/Editors/Results
// XXX do we fix this or revise how/when filters work???
// ...including accounting for variables/expansions and the like...
// XXX REVISE...
// XXX UPDATE...
filter: function(parser, args, body, state, expand=true){
var that = this var that = this
var outer = state.filters = delete args.text
state.filters ?? [] delete args.body
var local = Object.keys(args) var filters = Object.keys(args)
// trigger quote-filter... // local filter...
var quote = local if(body){
.map(function(filter){ // stage I
return (that.filters[filter] ?? {})['quote'] ?? [] }) body = this.expand(page, body, state)
.flat()
quote.length > 0
&& parser.macros['quote-filter'].call(
this,
parser,
Object.fromEntries(Object.entries(quote)),
null,
state)
// local filters...
if(body != null){
// expand the body...
var ast = expand ?
this.__parser__.expand(this, body, state)
: body instanceof Array ?
body
// NOTE: wrapping the body in an array effectively
// escapes it from parsing...
: [body]
// stage II
return function(state){ return function(state){
// XXX can we loose stuff from state this way??? body = that.resolve(page, body, state)
// ...at this stage it should more or less be static -- check!
return Promise.awaitOrRun( // stage III
// XXX how do we resolve the await loop? return function(state){
parser.execNested(this, ast, { return Promise.awaitOrRun(
...state, that.merge(page, body, state),
filters: local.includes(this.ISOLATED_FILTERS) ? function(body){
local // apply the filters...
: [...outer, ...local], // XXX combine with state.filters???
}), return that.applyFilters(filters, body, state) }) } }
function(res){
return {data: res} }) } // global filter...
// global filters... } else if(filters.length > 0){
} else { (state.filters = (state.filters ??= []))
state.filters = [...outer, ...local] } }, .push(...filters) }
return '' },
// Args... // Args...
@ -1286,9 +1280,7 @@ module.parser = {
// not 100% correct manner focusing on path depth and ignoring // not 100% correct manner focusing on path depth and ignoring
// the context, this potentially can lead to false positives. // the context, this potentially can lead to false positives.
// //
// XXX do we need the <context/> nested macro??? // XXX FILTER do we skip includes from outer filters???
// XXX should this resolve join and/or body in the context of the
// included page or the outer page (current)???
// XXX add path recursion test to data -- fail if two paths resolve // XXX add path recursion test to data -- fail if two paths resolve
// to the same context... // to the same context...
// XXX need a way to make encode option transparent... // XXX need a way to make encode option transparent...
@ -1297,9 +1289,6 @@ module.parser = {
include: Macro( include: Macro(
['src', 'recursive', 'join', ['src', 'recursive', 'join',
['s', 'strict', 'isolated']], ['s', 'strict', 'isolated']],
// XXX thinking that reimplementing this is a bit less boring than
// refactoring, and should be cleaner...
// XXX if the src is empty return nothing...
// XXX need a wrapper protocol -- is this the level for it??? // XXX need a wrapper protocol -- is this the level for it???
// XXX page API used: // XXX page API used:
// .resolvePathVars(path) // .resolvePathVars(path)
@ -1337,6 +1326,7 @@ module.parser = {
handler ??= handler ??=
function(page, body, path, text, state){ function(page, body, path, text, state){
// re-include limit... // re-include limit...
//* XXX RECURSION
// XXX HACK??? // XXX HACK???
if( ++(state.included ??= {[path]: 0})[path] if( ++(state.included ??= {[path]: 0})[path]
> this.INCLUDE_NEST_LIMIT ?? 20){ > this.INCLUDE_NEST_LIMIT ?? 20){
@ -1357,19 +1347,24 @@ module.parser = {
throw new Error('Recursive macro: '+include_stack) } throw new Error('Recursive macro: '+include_stack) }
return that.expand(page, recursive, state) } return that.expand(page, recursive, state) }
include_stack.push(path) include_stack.push(path)
//*/
// XXX check cache??? // XXX check cache???
var nested var nested
var res = args.isolated ? var res = args.isolated ?
this.resolve( //this.resolve(
this.merge(
page, page,
text, text,
nested = args.isolated == 'partial' ? nested = args.isolated == 'partial' ?
serialize.partialDeepCopy(state) serialize.partialDeepCopy(state)
: {}) : {})
// XXX FILTER need to localize target page
// filters to it, somehow...
: this.expand(page, text, state) : this.expand(page, text, state)
//* XXX RECURSION
// handle recursion... // handle recursion...
Promise.awaitOrRun( Promise.awaitOrRun(
(nested ?? {}).waitAll, (nested ?? {}).waitAll,
@ -1381,6 +1376,7 @@ module.parser = {
if(state.include_stack.length == 0){ if(state.include_stack.length == 0){
delete state.include_stack delete state.include_stack
delete state.recursive } }) delete state.recursive } })
//*/
return res } return res }
@ -1491,6 +1487,10 @@ module.parser = {
quoting( quoting(
function(page, args, body, state){ function(page, args, body, state){
var that = this var that = this
var filters = (args.filter ?? '')
.split(/\s+/)
.filter(function(s){
return s.length > 0 })
return Promise.awaitOrRun( return Promise.awaitOrRun(
args.src args.src
&& this.execNested(page, args.src, state), && this.execNested(page, args.src, state),
@ -1507,10 +1507,9 @@ module.parser = {
function(text){ function(text){
return that.joinBlocks( return that.joinBlocks(
page, page,
that.filterBlocks( that.applyFilters(
page, filters,
text, text,
args.filter,
state), state),
args.join, args.join,
state) }) }) })), state) }) }) })),