diff --git a/v3/pwiki/parser.js b/v3/pwiki/parser.js
index 00bb705..6c9f308 100644
--- a/v3/pwiki/parser.js
+++ b/v3/pwiki/parser.js
@@ -600,7 +600,13 @@ module.BaseParser = {
elem.resolving = res
wait.add(res)
state.waitAll = res
- // XXX is .isolated implemented???
+ // XXX do we need to wait till the last .waitNested is
+ // resolved?
+ // ...should it's handlers complete??
+ // XXX can this be controlled by the macro???
+ // ...one way to do in is to ger pass a resolve(..)
+ // func to the macro...
+ // ...do we need this?
if(!res.isolated){
state.waitNested = res }
res.then(
@@ -720,40 +726,35 @@ module.BaseParser = {
callback) } },
// XXX
+ _parse: function(page, ast, state={}){
+ return Promise.awaitOrRun(
+ this.resolve(page, ast, state),
+ function(ast){
+ // XXX
+ if(ast.length > 1){
+ throw new Error('!!!!')
+ }
+ return ast[0]
+ ?? '' }) },
+ // XXX
// XXX how should this play with filters???
// ...should filters be client-side only??
parseNested: function(page, ast, state={}){
- var that = this
- ast = this.resolve(page, ast, state)
- // XXX
- if(state.waitNested){
- return state.waitNested
- .then(function(){
- return that.parse(page, ast, state) }) }
- // XXX
- if(ast.length > 1){
- throw new Error('!!!!')
- }
- return ast[0]
- ?? '' },
+ return Promise.awaitOrRun(
+ state.waitNested,
+ this._parse(page, ast, state),
+ function(_, ast){
+ return ast }) },
// XXX this can't be used from within macros -- will deadlock the results...
// XXX how should this play with filters???
// ...should filters be client-side only??
parse: function(page, ast, state={}){
- var that = this
- ast = this.resolve(page, ast, state)
- // XXX .wait or .waitAll ???
- if(state.wait){
- return state.wait
- .then(function(){
- return that.parse(page, ast, state) }) }
- // XXX
- if(ast.length > 1){
- throw new Error('!!!!')
- }
- return ast[0]
- ?? '' },
+ return Promise.awaitOrRun(
+ state.wait,
+ this._parse(page, ast, state),
+ function(_, ast){
+ return ast }) },
@@ -1002,6 +1003,13 @@ function(spec, func){
return func }
+var isolated =
+module.isolated =
+function(func){
+ func.isolated = true
+ return func }
+
+
// XXX RENAME...
// ...this is more of an expander/executer...
// ...might be a good idea to also do a check without executing...
@@ -1088,7 +1096,7 @@ module.parser = {
// ...at this stage it should more or less be static -- check!
return Promise.awaitOrRun(
// XXX how do we resolve the await loop?
- parser.parse(this, ast, {
+ parser.parseNested(this, ast, {
...state,
filters: local.includes(this.ISOLATED_FILTERS) ?
local
@@ -1364,23 +1372,26 @@ module.parser = {
// 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 this needs to be reusable...
// XXX need a wrapper protocol -- is this the level for it???
// XXX page API used:
- // .basepath
// .resolvePathVars(path)
// .get(path)
// is this a promise/value, iterable promise a generator
// an async generator, ... or a combination/stack of the above???
function(parser, args, body, state, key='included', handler){
+ var that = this
+
+ var recursive =
+ state.recursive =
+ args.recursive
+ ?? body
+ ?? state.recursive
var base = this.basepath
- // XXX
- //var src = parser.parse(this.resolvePathVars(args.src))
- var src = args.src
+ var src = this.resolvePathVars(args.src)
return Promise.awaitOrRun(
- parser.parse(this, src, state),
+ parser.parseNested(this, src, state),
function(src){
var cache = state.cache ??= {}
if(cache[src]){
@@ -1389,36 +1400,72 @@ module.parser = {
// XXX should this be a tree??
// ...need to at least split direct and
// indirect dependencies...
- var depends = ((state.depends ??= {})[base] ??= {})
+ // XXX would be nice to separate direct (in-page)
+ // depenedencies nad nested...
+ // XXX do we need the same for real paths???
+ // no, because actual paths are meaningless
+ // out of context...
+ var depends = ((state.depends ??= {})[src] ??= {})
+ // check for recursion...
+ // XXX do we do this for pattern paths???
+ // XXX this does not catch the /A/A/A/... recursion...
+ var stack = state.include_stack ??= []
+ // XXX is this the right separator???
+ // ...need something that can't be in a path...
+ var base_src = base +'|'+ src
+ if(stack.includes(base_src)){
+ if(recursive){
+ return recursive }
+ throw new Error('Recursion:\n\t'+
+ [...stack, base_src].join('\n\t\t-> ')) }
+ stack.push(base_src)
+
+ // content handler...
handler ??=
- function(parser, page, state){
- // XXX get page text
- // XXX setup state
- return parser.parse(this, page, state) }
- var pageHandler =
- function(page){
- // XXX cache...
- return handler.call(this, parser, page, state) }
+ function(parser, text, state){
+ return parser._parse(that, text, state) }
- // XXX can we do:
- // return this.get(...)
- // .iter()
- // .map(...)
- // .sync()
- return Promise.awaitOrRun(
- this.get(src),
+ var pageHandler =
+ function(text, i, l){
+ return [
+ handler.call(that, parser, text, state),
+ // join...
+ (args.join
+ && i < l.length - 1) ?
+ parser._parse(that, args.join, state)
+ : []
+ ].flat() }
+ var resultHandler =
function(pages){
+ // XXX not sure if this can happen or why...
+ if(state.include_stack.at(-1) != base_src){
+ throw new Error('Include stack error') }
+ state.include_stack.pop()
+ // cleanup...
+ if(state.include_stack.length == 0){
+ delete state.include_stack
+ delete state.recursive }
+ // cache the final result...
+ // XXX wrap??
+ cache[src] = pages
+ return pages }
+
+ // get and run things...
+ return Promise.awaitOrRun(
+ that.get(src).raw,
+ function(pages){
+ pages = pages instanceof Array ?
+ pages
+ : [pages]
return Promise.awaitOrRun(
// handle pages...
Promise
- .iter(
- pages
- .map(pageHandler))
+ .iter(pages
+ .map( pageHandler ))
+ .flat()
.sync(),
- // cache the final result...
- function(pages){
- return (cache[src] = pages) }) }) }) }),
+ resultHandler ) }) }) }),
include: Macro(
['src', 'recursive', 'join',
@@ -1947,5 +1994,32 @@ module.parser = {
+// XXX for testing...
+
+var P =
+module.P = {
+ //* XXX
+ _content: [
+ 'first page text',
+ 'second page text',
+ ],
+ /*/
+ _content: 'page text',
+ //*/
+
+ path: '/path/to/page',
+ basepath: '/path/to/',
+
+ get raw(){
+ return this._content ?? '' },
+ get: function(){
+ return this },
+
+ resolvePathVars: function(path){
+ return path },
+}
+
+
+
/**********************************************************************
* vim:set ts=4 sw=4 : */ return module })
diff --git a/v3/pwiki/test/parser.js b/v3/pwiki/test/parser.js
index 18aa4af..a216e9b 100755
--- a/v3/pwiki/test/parser.js
+++ b/v3/pwiki/test/parser.js
@@ -73,6 +73,12 @@ test.Setups({
'[[ ]]@slot(slot value)',
'value' ]} },
+ // XXX should this work???
+ slot_nested_nested: function(assert){
+ return {code: [
+ '[[ ]]',
+ 'value' ]} },
+
/* XXX SHOWN_HIDDEN
// XXX these need to be revised...
// ...do we actually need hidden/shown???