refactores slot's <content/> now seems to work...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2026-06-27 17:06:21 +03:00
parent bedab9962a
commit f2a47de99f

View File

@ -19,6 +19,8 @@ var pwpath = require('./path')
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// Parser... // Parser...
// XXX TODO:
// callbacks on elements resolving...
// XXX ASAP move the macros here... // XXX ASAP move the macros here...
// XXX should we warn about stuff like <macro src=/moo/> -- currently // XXX should we warn about stuff like <macro src=/moo/> -- currently
// this will simply be ignored, i.e. passed trough the parser // this will simply be ignored, i.e. passed trough the parser
@ -471,7 +473,13 @@ module.BaseParser = {
// //
// //
// <state> ::= { // <state> ::= {
// // wait for last non-isolated...
// waitNested: <promise> | null, // waitNested: <promise> | null,
//
// // wait for last isolated...
// waitAll: <promise> | null,
//
// // wait for all...
// wait: <promise> | null, // wait: <promise> | null,
// } // }
// //
@ -517,7 +525,6 @@ module.BaseParser = {
ast ast
: ast.iter() : ast.iter()
// XXX revise names...
var wait = new Set() var wait = new Set()
state.wait instanceof Promise state.wait instanceof Promise
&& wait.add(state.wait) && wait.add(state.wait)
@ -540,8 +547,11 @@ module.BaseParser = {
var {name, args, body} = elem var {name, args, body} = elem
// XXX revise -- do we need this???
// nested macro -- skip... // nested macro -- skip...
if(that.macros[name] instanceof Array){
elems.push({...elem})
continue }
// drop non-macros/aliases...
if(typeof(that.macros[name]) != 'function' if(typeof(that.macros[name]) != 'function'
&& typeof(that.macros[name]) != 'string'){ && typeof(that.macros[name]) != 'string'){
continue } continue }
@ -558,11 +568,15 @@ module.BaseParser = {
if(res instanceof Promise){ if(res instanceof Promise){
elem.resolving = res elem.resolving = res
wait.add(res) wait.add(res)
state.waitAll = res
// XXX is .isolated implemented???
if(!res.isolated){ if(!res.isolated){
state.waitNested = res } state.waitNested = res }
res.then( res.then(
function(value){ function(value){
wait.delete(res) wait.delete(res)
if(state.waitAll === res){
delete state.waitAll }
if(state.waitNested === res){ if(state.waitNested === res){
delete state.waitNested } delete state.waitNested }
delete elem.resolving delete elem.resolving
@ -650,18 +664,32 @@ module.BaseParser = {
if(elem instanceof Array){ if(elem instanceof Array){
merge(...this.resolve(page, elem, state)) merge(...this.resolve(page, elem, state))
continue } continue }
// nested macro with no value set -- skip...
if(this.macros[elem.name] instanceof Array){
continue }
// unresolved... // unresolved...
merge(elem) } merge(elem) }
return elems }, return elems },
// XXX render api...
// XXX how should this play with filters???
// ...should filters be client-side only??
render: function*(page, ast, callback, state={}){
ast = this.resolve(page, ast, state)
for(var elem of ast){
yield Promise.awaitOrRun(
elem,
callback) } },
// XXX // XXX
// XXX how should this play with filters???
// ...should filters be client-side only??
parseNested: function(page, ast, state={}){ parseNested: function(page, ast, state={}){
var that = this var that = this
ast = this.resolve(page, ast, state) ast = this.resolve(page, ast, state)
// XXX // XXX
if(state.waitNested){ if(state.waitNested){
// XXX for some odd reason returning this breaks everything...
return state.waitNested return state.waitNested
.then(function(){ .then(function(){
return that.parse(page, ast, state) }) } return that.parse(page, ast, state) }) }
@ -671,12 +699,14 @@ module.BaseParser = {
} }
return ast[0] }, return ast[0] },
// 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={}){ parse: function(page, ast, state={}){
var that = this var that = this
ast = this.resolve(page, ast, state) ast = this.resolve(page, ast, state)
// XXX // XXX .wait or .waitAll ???
if(state.wait){ if(state.wait){
// XXX for some odd reason returning this breaks everything...
return state.wait return state.wait
.then(function(){ .then(function(){
return that.parse(page, ast, state) }) } return that.parse(page, ast, state) }) }
@ -1092,9 +1122,8 @@ module.parser = {
return '' } return '' }
return Promise.awaitOrRun( return Promise.awaitOrRun(
state.waitNested,
parser.parseNested(this, name, state), parser.parseNested(this, name, state),
function(_, name){ function(name){
// XXX INC_DEC // XXX INC_DEC
var inc = args.inc var inc = args.inc
var dec = args.dec var dec = args.dec
@ -1163,9 +1192,9 @@ module.parser = {
// set... // set...
if(text){ if(text){
return Promise.awaitOrRun( return Promise.awaitOrRun(
state.waitNested, //state.waitNested,
parser.parseNested(this, text, state), parser.parseNested(this, text, state),
function(_, value){ function(value){
text = vars[name] = value text = vars[name] = value
return show ?? false ? return show ?? false ?
text text
@ -1218,6 +1247,12 @@ module.parser = {
// This also works for cases where slots override slots they // This also works for cases where slots override slots they
// are contained in, this will not lead to recursion. // are contained in, this will not lead to recursion.
// //
// XXX do we show a slot with unfilled content???
// ...what's the point in having <content>, can't is just
// be replaced by a slot?
// ...content + hidden allows us not just to fill a slot
// but to also place it...
// XXX revise/document how shown/hidden work...
// XXX revise the use of hidden/shown use mechanic and if it's // XXX revise the use of hidden/shown use mechanic and if it's
// needed... // needed...
slot: Macro( slot: Macro(
@ -1230,10 +1265,8 @@ module.parser = {
// correctly... // correctly...
?? [] ?? []
return Promise.awaitOrRun( return Promise.awaitOrRun(
state.waitNested, parser.parseNested(this, name, state),
name function(name){
|| parser.parseNested(this, name, state),
function(_, name){
var slots = state.slots ??= {} var slots = state.slots ??= {}
//var hidden = name in slots //var hidden = name in slots
@ -1260,15 +1293,18 @@ module.parser = {
// handle <content/>... // handle <content/>...
for(prev of stack){ for(prev of stack){
// get the first <content/> // get the first <content/>
for(var i in slot){ // XXX this is a flat search, should be deep...
if(typeof(slot[i]) != 'string' for(var i in prev){
&& slot[i].name == 'content'){ if(typeof(prev[i]) != 'string'
&& prev[i].name == 'content'){
break } break }
i = null } i = null }
i != null i != null
&& slot.splice(i, 1, && (prev[i].value = [...slot])
&& slot.splice(0, slot.length,
...prev ...prev
// remove nested slot handlers... // remove nested slot handlers...
// XXX do we need this???
.filter(function(e){ .filter(function(e){
return typeof(e) != 'function' return typeof(e) != 'function'
|| e.slot != name }) ) } || e.slot != name }) ) }
@ -1276,7 +1312,8 @@ module.parser = {
'' ''
: Object.assign( : Object.assign(
function(st){ function(st){
return ((st ?? state).slots ?? {})[name] ?? original }, return ((st ?? state).slots ?? {})[name]
?? original },
{slot: name}) }) }), {slot: name}) }) }),
'content': ['slot'], 'content': ['slot'],