mirror of
https://github.com/flynx/pWiki.git
synced 2026-10-03 12:51:40 +00:00
Compare commits
No commits in common. "2ad186888e75c903c61a9c3375accfe7c656c2b6" and "e7dc0194ad129b613219773396f56c8668b81fb6" have entirely different histories.
2ad186888e
...
e7dc0194ad
@ -418,7 +418,7 @@ module.BaseParser = {
|
|||||||
: lex
|
: lex
|
||||||
|
|
||||||
var quoting = to
|
var quoting = to
|
||||||
&& !!this.macros[to].quoting
|
&& (page.QUOTING_MACROS ?? []).includes(to)
|
||||||
&& []
|
&& []
|
||||||
|
|
||||||
// NOTE: we are not using for .. of .. here as it depletes the
|
// NOTE: we are not using for .. of .. here as it depletes the
|
||||||
@ -530,8 +530,6 @@ module.BaseParser = {
|
|||||||
//
|
//
|
||||||
// // wait for all...
|
// // wait for all...
|
||||||
// wait: <promise> | null,
|
// wait: <promise> | null,
|
||||||
//
|
|
||||||
// ...
|
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@ -576,6 +574,14 @@ module.BaseParser = {
|
|||||||
ast
|
ast
|
||||||
: ast.iter()
|
: ast.iter()
|
||||||
|
|
||||||
|
var wait = new Set()
|
||||||
|
state.wait instanceof Promise
|
||||||
|
&& wait.add(state.wait)
|
||||||
|
var resolve, reject
|
||||||
|
state.wait = new Promise(
|
||||||
|
function(){
|
||||||
|
;[resolve, reject] = arguments })
|
||||||
|
|
||||||
var elems = []
|
var elems = []
|
||||||
for(let elem of ast){
|
for(let elem of ast){
|
||||||
// text block...
|
// text block...
|
||||||
@ -615,10 +621,9 @@ module.BaseParser = {
|
|||||||
var res = that.callMacro(page, name, args, body, state)
|
var res = that.callMacro(page, name, args, body, state)
|
||||||
// async...
|
// async...
|
||||||
if(res instanceof Promise){
|
if(res instanceof Promise){
|
||||||
let all, nested
|
|
||||||
all = state.waitAll =
|
|
||||||
Promise.all([state.waitAll, res])
|
|
||||||
elem.resolving = res
|
elem.resolving = res
|
||||||
|
wait.add(res)
|
||||||
|
state.waitAll = res
|
||||||
// XXX do we need to wait till the last .waitNested is
|
// XXX do we need to wait till the last .waitNested is
|
||||||
// resolved?
|
// resolved?
|
||||||
// ...should it's handlers complete??
|
// ...should it's handlers complete??
|
||||||
@ -627,13 +632,13 @@ module.BaseParser = {
|
|||||||
// func to the macro...
|
// func to the macro...
|
||||||
// ...do we need this?
|
// ...do we need this?
|
||||||
if(!res.isolated){
|
if(!res.isolated){
|
||||||
nested = state.waitNested =
|
state.waitNested = res }
|
||||||
Promise.all([state.waitNested, res]) }
|
|
||||||
res.then(
|
res.then(
|
||||||
function(value){
|
function(value){
|
||||||
if(state.waitAll === all){
|
wait.delete(res)
|
||||||
|
if(state.waitAll === res){
|
||||||
delete state.waitAll }
|
delete state.waitAll }
|
||||||
if(state.waitNested === nested){
|
if(state.waitNested === res){
|
||||||
delete state.waitNested }
|
delete state.waitNested }
|
||||||
delete elem.resolving
|
delete elem.resolving
|
||||||
elem.value = value
|
elem.value = value
|
||||||
@ -654,52 +659,25 @@ module.BaseParser = {
|
|||||||
elem = res }
|
elem = res }
|
||||||
elems.push(elem) }
|
elems.push(elem) }
|
||||||
|
|
||||||
// cleanup...
|
// handle wait for isolated macros to resolve...
|
||||||
var wait
|
var done = function(){
|
||||||
var waitAll = state.waitAll
|
resolve(state)
|
||||||
state.waitAll
|
delete state.wait }
|
||||||
&& state.waitAll
|
if(wait.size > 0){
|
||||||
.then(function(){
|
Promise.all(wait)
|
||||||
// only cleanup our own mess =)
|
.then(
|
||||||
waitAll === state.waitAll
|
done,
|
||||||
&& (delete state.waitAll) })
|
function(err){
|
||||||
&& (wait = state.wait = waitAll
|
reject(err) })
|
||||||
.then(function(){
|
// done...
|
||||||
wait === state.wait
|
} else {
|
||||||
&& (delete state.wait)
|
done() }
|
||||||
return elems }))
|
|
||||||
var waitNested = state.waitNested
|
|
||||||
state.waitNested
|
|
||||||
&& state.waitNested
|
|
||||||
.then(function(){
|
|
||||||
// only cleanup our own mess =)
|
|
||||||
waitNested === state.waitNested
|
|
||||||
&& (delete state.waitNested) })
|
|
||||||
|
|
||||||
return elems },
|
return elems },
|
||||||
|
|
||||||
// resolve stage II macros and merge results...
|
// resolve stage II macros and merge results...
|
||||||
//
|
//
|
||||||
/* XXX
|
// XXX BUG: sync/async paths seem to diverge...
|
||||||
// XXX these yeild different results:
|
|
||||||
// r = parser.resolve(
|
|
||||||
// tests.P,
|
|
||||||
// '<slot X>@include(/async/page)</slot> <slot X value>',
|
|
||||||
// s = {})
|
|
||||||
// s.wait.then(function(){
|
|
||||||
// console.log(r) }) // -> ['Page '] (err)
|
|
||||||
// and:
|
|
||||||
// r = parser.expand(
|
|
||||||
// tests.P,
|
|
||||||
// '<slot X>@include(/async/page)</slot> <slot X slot/>',
|
|
||||||
// s = {})
|
|
||||||
// s.wait.then(function(){
|
|
||||||
// r = parser.resolve(test.P, r, s)
|
|
||||||
// console.log(r) }) // -> ['slot '] (correct)
|
|
||||||
// -> promises seem to not be sequenced correctly here...
|
|
||||||
// XXX it looks like the first slot is resolved before the last
|
|
||||||
// slot has a chance to set the value as it is waiting for
|
|
||||||
// the first slot to finish...
|
|
||||||
resolve: function(page, ast, state={}){
|
resolve: function(page, ast, state={}){
|
||||||
var that = this
|
var that = this
|
||||||
ast = typeof(ast) != 'object' ?
|
ast = typeof(ast) != 'object' ?
|
||||||
@ -727,89 +705,29 @@ module.BaseParser = {
|
|||||||
prev = '' }
|
prev = '' }
|
||||||
if(args.length > 0){
|
if(args.length > 0){
|
||||||
elems.push(args.shift()) } } }
|
elems.push(args.shift()) } } }
|
||||||
|
var unpack = function(elem){
|
||||||
|
// XXX
|
||||||
|
}
|
||||||
|
|
||||||
// XXX can we make this more granular and wait only where we need
|
|
||||||
// to wait?
|
|
||||||
// ....the wait is logical as we need to return a string here
|
|
||||||
// eventually.
|
|
||||||
// should this be split into .resolve(..) nad .merge(..)???
|
|
||||||
return Promise.awaitOrRun(
|
|
||||||
state.wait,
|
|
||||||
function(){
|
|
||||||
// XXX can ast be a promise???
|
|
||||||
// XXX elems can be unresolved -- need a merge strategy for them...
|
|
||||||
//var waiting = []
|
|
||||||
for(var elem of ast){
|
|
||||||
// nesting...
|
|
||||||
while(elem && elem.value){
|
|
||||||
elem = elem.value
|
|
||||||
// exec stage II macros...
|
|
||||||
// XXX this should be called when all the promises before
|
|
||||||
// are resolved...
|
|
||||||
if(typeof(elem) == 'function'){
|
|
||||||
elem = elem(state) } }
|
|
||||||
if(elem == null){
|
|
||||||
continue }
|
|
||||||
// atomic values...
|
|
||||||
if(typeof(elem) != 'object'){
|
|
||||||
merge(elem)
|
|
||||||
continue }
|
|
||||||
// value is resolved but "empty" -> skip...
|
|
||||||
if('value' in elem
|
|
||||||
&& (elem.value == null
|
|
||||||
|| elem.value == '')){
|
|
||||||
continue }
|
|
||||||
// expand ast...
|
|
||||||
if(elem instanceof Array){
|
|
||||||
// XXX this can be or containe promises...
|
|
||||||
merge(...that.resolve(page, elem, state))
|
|
||||||
continue }
|
|
||||||
// expand .body attribute...
|
|
||||||
// XXX is this needed here???
|
|
||||||
if(elem.body instanceof Array){
|
|
||||||
console.warn('!!! RESOLVE_BODY')
|
|
||||||
// XXX this can be or containe promises...
|
|
||||||
elem.body = that.resolve(page, elem.body, state) }
|
|
||||||
// nested macro with no value set -- skip...
|
|
||||||
if(that.macros[elem.name] instanceof Array){
|
|
||||||
continue }
|
|
||||||
// unresolved...
|
|
||||||
merge(elem) }
|
|
||||||
|
|
||||||
return elems }) },
|
|
||||||
//*/
|
|
||||||
resolve: function(page, ast, state={}){
|
|
||||||
var that = this
|
|
||||||
ast = typeof(ast) != 'object' ?
|
|
||||||
this.expand(page, ast, state)
|
|
||||||
: ast instanceof types.Generator ?
|
|
||||||
ast
|
|
||||||
: ast.iter()
|
|
||||||
|
|
||||||
// merge resolved elements into the last item of elems...
|
|
||||||
// XXX can ast be a promise???
|
// XXX can ast be a promise???
|
||||||
// XXX elems can be unresolved -- need a merge strategy for them...
|
// XXX elems can be unresolved -- need a merge strategy for them...
|
||||||
var elems = []
|
|
||||||
for(var elem of ast){
|
for(var elem of ast){
|
||||||
// nesting...
|
// nesting...
|
||||||
while(elem && elem.value){
|
while(elem && elem.value){
|
||||||
|
elem = elem.value
|
||||||
// exec stage II macros...
|
// exec stage II macros...
|
||||||
if(typeof(elem.value) == 'function'){
|
if(typeof(elem) == 'function'){
|
||||||
let e = elem
|
elem = elem(state) } }
|
||||||
// NOTE: if not everything is resolved, delay the stage II
|
|
||||||
// callbacks till .wait is done...
|
|
||||||
Promise.awaitOrRun(
|
|
||||||
state.wait,
|
|
||||||
function(){
|
|
||||||
return elem = e.value =
|
|
||||||
e.value(state) })
|
|
||||||
break }
|
|
||||||
elem = elem.value }
|
|
||||||
if(elem == null){
|
if(elem == null){
|
||||||
continue }
|
continue }
|
||||||
|
// XXX do a delayed merge...
|
||||||
|
// ...but for this we need to also apply the rest of this iteration to the result...
|
||||||
|
if(elem.resolving){
|
||||||
|
console.log('!!!!!!!!!!!!!!!!!!!')
|
||||||
|
}
|
||||||
// atomic values...
|
// atomic values...
|
||||||
if(typeof(elem) != 'object'){
|
if(typeof(elem) != 'object'){
|
||||||
elems.push(elem)
|
merge(elem)
|
||||||
continue }
|
continue }
|
||||||
// value is resolved but "empty" -> skip...
|
// value is resolved but "empty" -> skip...
|
||||||
if('value' in elem
|
if('value' in elem
|
||||||
@ -818,48 +736,61 @@ module.BaseParser = {
|
|||||||
continue }
|
continue }
|
||||||
// expand ast...
|
// expand ast...
|
||||||
if(elem instanceof Array){
|
if(elem instanceof Array){
|
||||||
// XXX this can be or containe promises...
|
// XXX this can containe promises...
|
||||||
elems.push(...that.resolve(page, elem, state))
|
merge(...this.resolve(page, elem, state))
|
||||||
continue }
|
continue }
|
||||||
// expand .body attribute...
|
// expand .body attribute...
|
||||||
/* XXX is this needed here???
|
if((elem.attrs ?? {}).body instanceof Array){
|
||||||
if(elem.body instanceof Array){
|
// XXX this can containe promises...
|
||||||
console.warn('!!! RESOLVE_BODY')
|
elem.attrs.body = this.resolve(page, elem.attrs.body, state) }
|
||||||
// XXX this can be or containe promises...
|
|
||||||
elem.body = that.resolve(page, elem.body, state) }
|
|
||||||
//*/
|
|
||||||
// nested macro with no value set -- skip...
|
// nested macro with no value set -- skip...
|
||||||
if(that.macros[elem.name] instanceof Array){
|
if(this.macros[elem.name] instanceof Array){
|
||||||
continue }
|
continue }
|
||||||
// unresolved...
|
// unresolved...
|
||||||
elems.push(elem) }
|
merge(elem) }
|
||||||
|
|
||||||
return elems },
|
return elems },
|
||||||
|
|
||||||
|
|
||||||
// XXX render api...
|
// XXX render api...
|
||||||
// XXX how should this play with filters???
|
// XXX how should this play with filters???
|
||||||
// ...should filters be client-side only??
|
// ...should filters be client-side only??
|
||||||
render: function*(page, ast, callback, state={}){
|
render: function*(page, ast, callback, state={}){
|
||||||
// XXX
|
ast = this.resolve(page, ast, state)
|
||||||
},
|
for(var elem of ast){
|
||||||
|
yield Promise.awaitOrRun(
|
||||||
|
elem,
|
||||||
|
callback) } },
|
||||||
|
|
||||||
// XXX
|
// XXX
|
||||||
parse: function(page, ast, state={}, wait='wait'){
|
_parse: function(page, ast, state={}){
|
||||||
var that = this
|
|
||||||
var reresolve = !!state.wait
|
|
||||||
return Promise.awaitOrRun(
|
return Promise.awaitOrRun(
|
||||||
this.resolve(page, ast, state),
|
this.resolve(page, ast, state),
|
||||||
state[wait],
|
function(ast){
|
||||||
function(ast, reresolve){
|
// XXX
|
||||||
ast = reresolve ?
|
if(ast.length > 1){
|
||||||
that.resolve(page, ast, state)
|
throw new Error('!!!!')
|
||||||
: ast
|
}
|
||||||
return (ast ?? '').join('') }) },
|
return ast[0]
|
||||||
|
?? '' }) },
|
||||||
|
// XXX
|
||||||
// XXX how should this play with filters???
|
// XXX how should this play with filters???
|
||||||
// ...should filters be client-side only??
|
// ...should filters be client-side only??
|
||||||
parseNested: function(page, ast, state={}){
|
parseNested: function(page, ast, state={}){
|
||||||
return this.parse(page, ast, state, 'waitNestedi') },
|
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={}){
|
||||||
|
return Promise.awaitOrRun(
|
||||||
|
state.wait,
|
||||||
|
this._parse(page, ast, state),
|
||||||
|
function(_, ast){
|
||||||
|
return ast }) },
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1121,12 +1052,6 @@ function(macro){
|
|||||||
macro.lazy = true
|
macro.lazy = true
|
||||||
return macro }
|
return macro }
|
||||||
|
|
||||||
var quoting =
|
|
||||||
module.quoting =
|
|
||||||
function(macro){
|
|
||||||
macro.quoting = true
|
|
||||||
return macro }
|
|
||||||
|
|
||||||
|
|
||||||
// XXX RENAME...
|
// XXX RENAME...
|
||||||
// ...this is more of an expander/executer...
|
// ...this is more of an expander/executer...
|
||||||
@ -1135,6 +1060,9 @@ var parser =
|
|||||||
module.parser = {
|
module.parser = {
|
||||||
__proto__: BaseParser,
|
__proto__: BaseParser,
|
||||||
|
|
||||||
|
// list of macros that will get raw text of their content...
|
||||||
|
QUOTING_MACROS: ['quote'],
|
||||||
|
|
||||||
//
|
//
|
||||||
// <macro>(<args>, <body>, <state>){ .. }
|
// <macro>(<args>, <body>, <state>){ .. }
|
||||||
// -> undefined
|
// -> undefined
|
||||||
@ -1530,7 +1458,7 @@ module.parser = {
|
|||||||
// is this a promise/value, iterable promise a generator
|
// is this a promise/value, iterable promise a generator
|
||||||
// an async generator, ... or a combination/stack of the above???
|
// an async generator, ... or a combination/stack of the above???
|
||||||
lazy(
|
lazy(
|
||||||
function(page, args, body, state, handler){
|
function(page, args, body, state, key='included', handler){
|
||||||
var that = this
|
var that = this
|
||||||
|
|
||||||
var recursive =
|
var recursive =
|
||||||
@ -1577,28 +1505,28 @@ module.parser = {
|
|||||||
// content handler...
|
// content handler...
|
||||||
handler ??=
|
handler ??=
|
||||||
function(page, text, state){
|
function(page, text, state){
|
||||||
// XXX should this be the difference between
|
return this._parse(page, text, state) }
|
||||||
// @include(..) and @source(..)???
|
|
||||||
// i.e.
|
|
||||||
// .include(..) -> .resolve(..)
|
|
||||||
// .source(..) -> .expand(..)
|
|
||||||
return args.isolated ?
|
|
||||||
this.resolve(page, text,
|
|
||||||
args.isolated == 'partial' ?
|
|
||||||
// XXX
|
|
||||||
serialize.partialDeepCopy(state)
|
|
||||||
: {})
|
|
||||||
: this.expand(page, text, state)}
|
|
||||||
|
|
||||||
var pageHandler =
|
var pageHandler =
|
||||||
function(text, i, l){
|
function(text, i, l){
|
||||||
return [
|
return [
|
||||||
handler.call(that, page, text, state),
|
handler.call(that,
|
||||||
|
page,
|
||||||
|
text,
|
||||||
|
// isolated up -- will see all
|
||||||
|
// the state but can have no
|
||||||
|
// side-effects...
|
||||||
|
args.isolated == 'partial' ?
|
||||||
|
serialize.partialDeepCopy(state)
|
||||||
|
// fully isolated...
|
||||||
|
: args.isolated ?
|
||||||
|
{}
|
||||||
|
: state),
|
||||||
// join...
|
// join...
|
||||||
(args.join
|
(args.join
|
||||||
&& i < l.length - 1) ?
|
&& i < l.length - 1) ?
|
||||||
that.expand(page, args.join, state)
|
that._parse(page, args.join, state)
|
||||||
: [],
|
: []
|
||||||
].flat() }
|
].flat() }
|
||||||
var resultHandler =
|
var resultHandler =
|
||||||
function(pages){
|
function(pages){
|
||||||
@ -1630,6 +1558,106 @@ module.parser = {
|
|||||||
.sync(),
|
.sync(),
|
||||||
resultHandler ) }) }) })),
|
resultHandler ) }) }) })),
|
||||||
|
|
||||||
|
_include: Macro(
|
||||||
|
['src', 'recursive', 'join',
|
||||||
|
['s', 'strict', 'isolated']],
|
||||||
|
async function*(parser, args, body, state, key='included', handler){
|
||||||
|
var macro = 'include'
|
||||||
|
if(typeof(args) == 'string'){
|
||||||
|
var [macro, args, body, state, key, handler] = arguments
|
||||||
|
key = key ?? 'included' }
|
||||||
|
var base = this.get(this.path.split(/\*/).shift())
|
||||||
|
var src = args.src
|
||||||
|
&& this.resolvePathVars(
|
||||||
|
await base.parse(args.src, state))
|
||||||
|
if(!src){
|
||||||
|
return }
|
||||||
|
// XXX INHERIT_ARGS special-case: inherit args by default...
|
||||||
|
// XXX should this be done when isolated???
|
||||||
|
if(this.actions_inherit_args
|
||||||
|
&& this.actions_inherit_args.has(pwpath.basename(src))
|
||||||
|
&& this.get(pwpath.dirname(src)).path == this.path){
|
||||||
|
src += ':$ARGS' }
|
||||||
|
var recursive = args.recursive ?? body
|
||||||
|
var isolated = args.isolated
|
||||||
|
var strict = args.strict
|
||||||
|
var strquotes = args.s
|
||||||
|
var join = args.join
|
||||||
|
&& await base.parse(args.join, state)
|
||||||
|
|
||||||
|
var depends = state.depends =
|
||||||
|
state.depends
|
||||||
|
?? new Set()
|
||||||
|
// XXX DEPENDS_PATTERN
|
||||||
|
depends.add(src)
|
||||||
|
|
||||||
|
handler = handler
|
||||||
|
?? async function(src, state){
|
||||||
|
return isolated ?
|
||||||
|
//{data: await this.get(src)
|
||||||
|
{data: await this
|
||||||
|
.parse({
|
||||||
|
seen: state.seen,
|
||||||
|
depends,
|
||||||
|
renderer: state.renderer,
|
||||||
|
})}
|
||||||
|
//: this.get(src)
|
||||||
|
: this
|
||||||
|
.parse(state) }
|
||||||
|
|
||||||
|
var first = true
|
||||||
|
for await (var page of this.get(src).asPages(strict)){
|
||||||
|
if(join && !first){
|
||||||
|
yield join }
|
||||||
|
first = false
|
||||||
|
|
||||||
|
//var full = page.path
|
||||||
|
var full = page.location
|
||||||
|
|
||||||
|
// handle recursion...
|
||||||
|
var parent_seen = 'seen' in state
|
||||||
|
var seen = state.seen =
|
||||||
|
new Set(state.seen ?? [])
|
||||||
|
if(seen.has(full)
|
||||||
|
// nesting path recursion...
|
||||||
|
|| (full.length % (this.NESTING_RECURSION_TEST_THRESHOLD || 50) == 0
|
||||||
|
&& (pwpath.split(full).length > 3
|
||||||
|
&& new Set([
|
||||||
|
await page.find(),
|
||||||
|
await page.get('..').find(),
|
||||||
|
await page.get('../..').find(),
|
||||||
|
]).size == 1
|
||||||
|
// XXX HACK???
|
||||||
|
|| pwpath.split(full).length > (this.NESTING_DEPTH_LIMIT || 20)))){
|
||||||
|
if(recursive == null){
|
||||||
|
console.warn(
|
||||||
|
`@${key}(..): ${
|
||||||
|
seen.has(full) ?
|
||||||
|
'direct'
|
||||||
|
: 'depth-limit'
|
||||||
|
} recursion detected:`, full, seen)
|
||||||
|
yield page.get(page.RECURSION_ERROR).parse()
|
||||||
|
continue }
|
||||||
|
// have the 'recursive' arg...
|
||||||
|
yield base.parse(recursive, state)
|
||||||
|
continue }
|
||||||
|
seen.add(full)
|
||||||
|
|
||||||
|
// load the included page...
|
||||||
|
var res = await handler.call(page, full, state)
|
||||||
|
depends.add(full)
|
||||||
|
res = strquotes ?
|
||||||
|
res
|
||||||
|
.replace(/["']/g, function(c){
|
||||||
|
return '%'+ c.charCodeAt().toString(16) })
|
||||||
|
: res
|
||||||
|
|
||||||
|
// NOTE: we only track recursion down and not sideways...
|
||||||
|
seen.delete(full)
|
||||||
|
if(!parent_seen){
|
||||||
|
delete state.seen }
|
||||||
|
|
||||||
|
yield res } }),
|
||||||
// NOTE: the main difference between this and @include is that
|
// NOTE: the main difference between this and @include is that
|
||||||
// this renders the src in the context of current page while
|
// this renders the src in the context of current page while
|
||||||
// include is rendered in the context of its page but with
|
// include is rendered in the context of its page but with
|
||||||
@ -1643,48 +1671,30 @@ module.parser = {
|
|||||||
['src', 'recursive', 'join',
|
['src', 'recursive', 'join',
|
||||||
['s', 'strict']],
|
['s', 'strict']],
|
||||||
//['src'],
|
//['src'],
|
||||||
function(page, args, body, state){
|
async function*(args, body, state){
|
||||||
var that = this
|
var that = this
|
||||||
return this.macros['include'].call(this,
|
yield* this.__parser__.macros.include.call(this,
|
||||||
page, args, body, state,
|
'source',
|
||||||
function(page, text, state){
|
args, body, state, 'sources',
|
||||||
return that.expand(page, text, state) }) }),
|
async function(src, state){
|
||||||
|
//return that.parse(that.get(src).raw, state) }) }),
|
||||||
|
return that.parse(this.raw, state) }) }),
|
||||||
|
|
||||||
// Load macro and slot definitions but ignore the page text...
|
// Load macro and slot definitions but ignore the page text...
|
||||||
//
|
//
|
||||||
// NOTE: this is essentially the same as @source(..) but returns ''.
|
// NOTE: this is essentially the same as @source(..) but returns ''.
|
||||||
// XXX revise name...
|
// XXX revise name...
|
||||||
|
// XXX UPDATE...
|
||||||
load: Macro(
|
load: Macro(
|
||||||
['src'],
|
['src', ['strict']],
|
||||||
function(args, body, state){
|
async function*(args, body, state){
|
||||||
var that = this
|
var that = this
|
||||||
return Promise.awaitOrRun(
|
yield* this.__parser__.macros.include.call(this,
|
||||||
this.macros['include'].call(this, page, args, body, state),
|
'load',
|
||||||
function(){
|
args, body, state, 'sources',
|
||||||
|
async function(src, state){
|
||||||
|
await that.parse(this.raw, state)
|
||||||
return '' }) }),
|
return '' }) }),
|
||||||
|
|
||||||
// XXX a naive version, see ._quote(..) for reference...
|
|
||||||
quote: Macro(
|
|
||||||
['src', 'join', 'filter'],
|
|
||||||
quoting(
|
|
||||||
function(page, args, body, state){
|
|
||||||
var res =
|
|
||||||
(args.src ?
|
|
||||||
page.get(args.src).raw
|
|
||||||
: body ?
|
|
||||||
body
|
|
||||||
: [])
|
|
||||||
return Promise.awaitOrRun(
|
|
||||||
res,
|
|
||||||
function(res){
|
|
||||||
// filter...
|
|
||||||
if(args.filter){
|
|
||||||
// XXX
|
|
||||||
}
|
|
||||||
// XXX join...
|
|
||||||
// XXX
|
|
||||||
return res }) })),
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// @quote(<src>)
|
// @quote(<src>)
|
||||||
//
|
//
|
||||||
@ -1707,7 +1717,7 @@ module.parser = {
|
|||||||
// XXX need a way to escape macros -- i.e. include </quote> in a quoted text...
|
// XXX need a way to escape macros -- i.e. include </quote> in a quoted text...
|
||||||
// XXX should join/else be sub-tags???
|
// XXX should join/else be sub-tags???
|
||||||
// XXX UPDATE...
|
// XXX UPDATE...
|
||||||
_quote: Macro(
|
quote: Macro(
|
||||||
['src', 'filter', 'text', 'join', 'else',
|
['src', 'filter', 'text', 'join', 'else',
|
||||||
['s', 'expandactions', 'strict']],
|
['s', 'expandactions', 'strict']],
|
||||||
async function*(args, body, state){
|
async function*(args, body, state){
|
||||||
@ -1817,7 +1827,6 @@ module.parser = {
|
|||||||
var filters = state.quote_filters =
|
var filters = state.quote_filters =
|
||||||
state.quote_filters ?? []
|
state.quote_filters ?? []
|
||||||
filters.splice(filters.length, 0, ...Object.keys(args)) },
|
filters.splice(filters.length, 0, ...Object.keys(args)) },
|
||||||
//*/
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// <macro src=<url>> .. </macro>
|
// <macro src=<url>> .. </macro>
|
||||||
|
|||||||
@ -17,7 +17,6 @@ module.exports.PAGES = {
|
|||||||
'/page': 'Page',
|
'/page': 'Page',
|
||||||
'/async/page': Promise.resolve('Page'),
|
'/async/page': Promise.resolve('Page'),
|
||||||
'/includePage': '@include(/page)',
|
'/includePage': '@include(/page)',
|
||||||
'/isolated': '@slot(slot original)'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var P =
|
var P =
|
||||||
@ -51,7 +50,6 @@ module.exports.P = {
|
|||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
test.Setups({
|
test.Setups({
|
||||||
// general parser...
|
|
||||||
empty: function(assert){
|
empty: function(assert){
|
||||||
return { code: [ '', '' ] }},
|
return { code: [ '', '' ] }},
|
||||||
|
|
||||||
@ -143,7 +141,11 @@ test.Setups({
|
|||||||
return {code: [
|
return {code: [
|
||||||
'<slot slot>moo<slot slot>[[ <content/> ]]</slot></slot>',
|
'<slot slot>moo<slot slot>[[ <content/> ]]</slot></slot>',
|
||||||
'[[ moo ]]' ]} },
|
'[[ moo ]]' ]} },
|
||||||
// shown/hidden..
|
|
||||||
|
/* XXX SHOWN_HIDDEN
|
||||||
|
// XXX these need to be revised...
|
||||||
|
// ...do we actually need hidden/shown???
|
||||||
|
//
|
||||||
slot_shown: function(assert){
|
slot_shown: function(assert){
|
||||||
var ins = this.slot_value(assert).code
|
var ins = this.slot_value(assert).code
|
||||||
var expect = ins.pop()
|
var expect = ins.pop()
|
||||||
@ -168,8 +170,9 @@ test.Setups({
|
|||||||
var expect = ins.pop()
|
var expect = ins.pop()
|
||||||
return {code: [
|
return {code: [
|
||||||
...ins.map(function(i){
|
...ins.map(function(i){
|
||||||
return i +' | @slot(slot shown)' }),
|
return i +'@slot(slot shown)' }),
|
||||||
' | value' ]} },
|
'' ]} },
|
||||||
|
//*/
|
||||||
|
|
||||||
// XXX var...
|
// XXX var...
|
||||||
// XXX
|
// XXX
|
||||||
@ -178,7 +181,7 @@ test.Setups({
|
|||||||
// XXX
|
// XXX
|
||||||
|
|
||||||
// include...
|
// include...
|
||||||
// XXX see inside...
|
// XXX these do not play well with modifiers...
|
||||||
include: function(assert, path='/blank', expected){
|
include: function(assert, path='/blank', expected){
|
||||||
return {
|
return {
|
||||||
page: P,
|
page: P,
|
||||||
@ -187,37 +190,18 @@ test.Setups({
|
|||||||
// XXX for some reason this does not parse int a macro....
|
// XXX for some reason this does not parse int a macro....
|
||||||
//'<include /blank />',
|
//'<include /blank />',
|
||||||
`<include "${path}" />`,
|
`<include "${path}" />`,
|
||||||
`<include src="${path}" />`,
|
expected
|
||||||
|
?? P.get(path).raw,
|
||||||
expected
|
|
||||||
?? P.get(path).raw,
|
|
||||||
],
|
],
|
||||||
}},
|
}},
|
||||||
include_page: function(assert){
|
include_page: function(assert){
|
||||||
return this.include(assert, '/page') },
|
return this.include(assert, '/page') },
|
||||||
include_include_page: function(assert){
|
include_include_page: function(assert){
|
||||||
return this.include(assert, '/includePage', 'Page') },
|
return this.include(assert, '/includePage', 'Page') },
|
||||||
|
/* XXX parser.resolve(..) does not handle promises correctly yet...
|
||||||
include_async: function(assert){
|
include_async: function(assert){
|
||||||
return this.include(assert, '/async/page', 'Page') },
|
return this.include(assert, '/async/page') },
|
||||||
// islotaed...
|
//*/
|
||||||
include_nonisolated: function(assert){
|
|
||||||
return {
|
|
||||||
page: P,
|
|
||||||
code:[
|
|
||||||
'@include("/isolated") @slot(slot overloaded)',
|
|
||||||
'overloaded ',
|
|
||||||
],
|
|
||||||
} },
|
|
||||||
include_isolated: function(assert){
|
|
||||||
return {
|
|
||||||
page: P,
|
|
||||||
code:[
|
|
||||||
'@include(isolated /isolated) @slot(slot overloaded)',
|
|
||||||
'original overloaded',
|
|
||||||
],
|
|
||||||
} },
|
|
||||||
// XXX recursion...
|
|
||||||
// XXX
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@ -250,7 +234,7 @@ test.Modifiers({
|
|||||||
|
|
||||||
|
|
||||||
test.Tests({
|
test.Tests({
|
||||||
parse: async function(assert, state){
|
parse: function(assert, state){
|
||||||
var {page, code, st} = state
|
var {page, code, st} = state
|
||||||
page ??= {}
|
page ??= {}
|
||||||
st ??= {}
|
st ??= {}
|
||||||
@ -263,7 +247,7 @@ test.Tests({
|
|||||||
var p = serialize.partialDeepCopy(page)
|
var p = serialize.partialDeepCopy(page)
|
||||||
var s = serialize.partialDeepCopy(st)
|
var s = serialize.partialDeepCopy(st)
|
||||||
assert(
|
assert(
|
||||||
(res = await parser.parse(
|
(res = parser.parse(
|
||||||
p,
|
p,
|
||||||
input,
|
input,
|
||||||
s))
|
s))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user