now args now working...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2022-05-16 11:54:21 +03:00
parent d40b9a96b1
commit a0b377d542

408
pwiki2.js
View File

@ -106,7 +106,6 @@ module.path = {
parent = this.normalize(parent, 'array') parent = this.normalize(parent, 'array')
return this.normalize(parent.concat(path), format) }, return this.normalize(parent.concat(path), format) },
//paths: function*(path='/', leading_slash=true){
paths: function*(path='/'){ paths: function*(path='/'){
path = this.normalize(path, 'array') path = this.normalize(path, 'array')
// handle '', '.', and '/' paths... // handle '', '.', and '/' paths...
@ -146,6 +145,10 @@ module.path = {
: parts) : parts)
.join('/'), .join('/'),
'string') }, 'string') },
basename: function(path){
return this.split(path).pop() },
dirname: function(path){
return this.relative(path, '..', 'string') },
} }
@ -948,14 +951,6 @@ module.BaseParser = {
return filter[0] != '-' }) return filter[0] != '-' })
.filter(function(filter){ .filter(function(filter){
return !skip.has(filter) })}, return !skip.has(filter) })},
/*/ XXX is this still used???
posArgs: function(args){
return Object.entries(args)
.reduce(function(res, [key, value]){
/^[0-9]+$/.test(key)
&& (res[key*1] = value)
return res }, []) },
//*/
// //
// Spec format: // Spec format:
// [<orderd>, ... [<keyword>, ...]] // [<orderd>, ... [<keyword>, ...]]
@ -1295,6 +1290,7 @@ module.parser = {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// XXX should these be something more generic like Object.assign(..) ???
// XXX revise... // XXX revise...
var Filter = var Filter =
@ -1305,6 +1301,19 @@ function(...args){
&& Object.assign(func, args.pop()) && Object.assign(func, args.pop())
return func } return func }
// XXX do we need anything else like .doc, attrs???
var Macro =
module.Macro =
function(spec, func){
var args = [...arguments]
// function...
func = args.pop()
// arg sepc...
;(args.length > 0 && args[args.length-1] instanceof Array)
&& (func.arg_spec = args.pop())
// XXX do we need anything else like .doc, attrs???
return func }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1405,7 +1414,7 @@ object.Constructor('Page', BasePage, {
[outer_filters] } [outer_filters] }
// merge in new filters... // merge in new filters...
var local = Object.values(args) var local = Object.keys(args)
filters.splice(filters.length, 0, ...local) filters.splice(filters.length, 0, ...local)
// trigger quote-filter... // trigger quote-filter...
@ -1460,59 +1469,63 @@ object.Constructor('Page', BasePage, {
// XXX should we track recursion via the resolved (current) path // XXX should we track recursion via the resolved (current) path
// or the given path??? // or the given path???
// XXX should this be lazy??? // XXX should this be lazy???
include: function(args, body, state, key='included', handler){ include: Macro(
// positional args... ['src', 'recursive', ['isolated']],
var src = args.src //|| args[0] function(args, body, state, key='included', handler){
var recursive = args.recursive || body // positional args...
var isolated = this.__parser__.posArgs(args).includes('isolated') var src = args.src
var recursive = args.recursive || body
var isolated = args.isolated
if(!src){ if(!src){
return '' } return '' }
handler = handler handler = handler
?? function(){ ?? function(){
return this.get(src) return this.get(src)
.parse( .parse(
isolated ? isolated ?
{[key]: state[key]} {[key]: state[key]}
: state) } : state) }
// handle recursion... // handle recursion...
var parent_seen = state[key] var parent_seen = state[key]
var seen = state[key] = var seen = state[key] =
(state[key] ?? [this.location]).slice() (state[key] ?? [this.location]).slice()
var target = this.match(src) var target = this.match(src)
target = target instanceof Array ? target = target instanceof Array ?
target.join(',') target.join(',')
: target : target
// recursion detected... // recursion detected...
if(this.match() == this.match(src) if(this.match() == this.match(src)
|| seen.includes(target)){ || seen.includes(target)){
if(!recursive){ if(!recursive){
throw new Error( throw new Error(
'include: include recursion detected: ' 'include: include recursion detected: '
+ seen.concat([target]).join(' -> ')) } + seen.concat([target]).join(' -> ')) }
// have the 'recursive' arg... // have the 'recursive' arg...
return this.__parser__.parse(this, recursive, state) } return this.__parser__.parse(this, recursive, state) }
seen.push(target) seen.push(target)
// load the included page... // load the included page...
var res = handler.call(this) var res = handler.call(this)
// restore previous include chain... // restore previous include chain...
if(parent_seen){ if(parent_seen){
state[key] = parent_seen state[key] = parent_seen
} else { } else {
delete state[key] } delete state[key] }
return res }, return res }),
source: function(args, body, state){ source: Macro(
var src = args.src //|| args[0] ['src'],
return this.macros.include.call(this, function(args, body, state){
args, body, state, 'sources', var src = args.src
function(){ return this.macros.include.call(this,
return this.__parser__.parse(this, this.get(src).raw +'', state) }) }, args, body, state, 'sources',
// function(){
return this.__parser__.parse(this, this.get(src).raw +'', state) }) }),
//
// @quote(<src>) // @quote(<src>)
// //
// <quote src=<src>[ filter="<filter> ..."]/> // <quote src=<src>[ filter="<filter> ..."]/>
@ -1531,53 +1544,55 @@ object.Constructor('Page', BasePage, {
// not expanded... // not expanded...
// //
// 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...
quote: function(args, body, state){ quote: Macro(
var src = args.src //|| args[0] ['src', 'filter', 'text'],
var text = args.text function(args, body, state){
?? body var src = args.src //|| args[0]
?? [] var text = args.text
text = src ? ?? body
// source page... ?? []
this.get(src).raw text = src ?
: text instanceof Array ? // source page...
text.join('') this.get(src).raw
: text : text instanceof Array ?
text.join('')
: text
// empty... // empty...
if(!text){ if(!text){
return } return }
var filters = var filters =
args.filter args.filter
&& args.filter && args.filter
.trim() .trim()
.split(/\s+/g) .split(/\s+/g)
// NOTE: we are delaying .quote_filters handling here to // NOTE: we are delaying .quote_filters handling here to
// make their semantics the same as general filters... // make their semantics the same as general filters...
// ...and since we are internally calling .filter(..) // ...and since we are internally calling .filter(..)
// macro we need to dance around it's architecture too... // macro we need to dance around it's architecture too...
// NOTE: since the body of quote(..) only has filters applied // NOTE: since the body of quote(..) only has filters applied
// to it doing the first stage of .filter(..) as late // to it doing the first stage of .filter(..) as late
// as the second stage here will have no ill effect... // as the second stage here will have no ill effect...
return function(state){ return function(state){
// add global quote-filters... // add global quote-filters...
filters = filters =
(state.quote_filters (state.quote_filters
&& !(filters ?? []).includes(this.ISOLATED_FILTERS)) ? && !(filters ?? []).includes(this.ISOLATED_FILTERS)) ?
[...state.quote_filters, ...(filters ?? [])] [...state.quote_filters, ...(filters ?? [])]
: filters : filters
if(filters){ if(filters){
filters = Object.fromEntries(Object.entries(filters)) filters = Object.fromEntries(Object.entries(filters))
return this.macros.filter return this.macros.filter
.call(this, filters, text, state, false) .call(this, filters, text, state, false)
.call(this, state) } .call(this, state) }
return text } }, return text } }),
// very similar to @filter(..) but will affect @quote(..) filters... // very similar to @filter(..) but will affect @quote(..) filters...
'quote-filter': function(args, body, state){ 'quote-filter': function(args, body, state){
var filters = state.quote_filters = var filters = state.quote_filters =
state.quote_filters ?? [] state.quote_filters ?? []
filters.splice(filters.length, 0, ...Object.values(args)) }, filters.splice(filters.length, 0, ...Object.keys(args)) },
// //
// <slot name=<name>/> // <slot name=<name>/>
// //
@ -1601,92 +1616,94 @@ object.Constructor('Page', BasePage, {
// //
// XXX how do we handle a slot defined within a slot???? // XXX how do we handle a slot defined within a slot????
// ...seems that we'll fall into recursion on definition... // ...seems that we'll fall into recursion on definition...
slot: function(args, body, state){ slot: Macro(
var name = args.name ['name', 'text', ['shown', 'hidden']],
var text = args.text function(args, body, state){
?? body var name = args.name
// NOTE: this can't be undefined for .expand(..) to work var text = args.text
// correctly... ?? body
?? [] // NOTE: this can't be undefined for .expand(..) to work
// correctly...
?? []
var slots = state.slots = var slots = state.slots =
state.slots state.slots
?? {} ?? {}
//var hidden = name in slots //var hidden = name in slots
// XXX EXPERIMENTAL // XXX EXPERIMENTAL
var pos = this.__parser__.posArgs(args) var hidden =
var hidden = // 'hidden' has priority...
// 'hidden' has priority... args.hidden
(pos.includes('hidden') || args.hidden) // explicitly show... ()
// explicitly show... () || (args.shown ?
|| ((pos.includes('shown') || args.shown) ? false
false // show first instance...
// show first instance... : name in slots)
: name in slots)
slots[name] = [...this.__parser__.expand(this, text, state)] slots[name] = [...this.__parser__.expand(this, text, state)]
return hidden ? return hidden ?
'' ''
: function(state){ : function(state){
return state.slots[name] } }, return state.slots[name] } }),
// XXX sorting not implemented yet.... // XXX sorting not implemented yet....
macro: function(args, body, state){ macro: Macro(
var that = this ['name', 'src', 'sort', 'text'],
var name = args.name //?? args[0] function(args, body, state){
var src = args.src var that = this
var sort = (args.sort ?? '') var name = args.name //?? args[0]
.split(/\s+/g) var src = args.src
.filter(function(e){ var sort = (args.sort ?? '')
return e != '' }) .split(/\s+/g)
var text = args.text .filter(function(e){
?? body return e != '' })
?? [] var text = args.text
?? body
?? []
if(name){ if(name){
// define new named macro... // define new named macro...
if(text){ if(text){
;(state.macros = state.macros ?? {})[name] = text ;(state.macros = state.macros ?? {})[name] = text
// use existing macro... // use existing macro...
} else if(state.macros } else if(state.macros
&& name in state.macros){ && name in state.macros){
text = state.macros[name] } } text = state.macros[name] } }
if(src){ if(src){
var pages = this.get(src).each() var pages = this.get(src).each()
// no matching pages -> get the else block... // no matching pages -> get the else block...
if(pages.length == 0 && text){ if(pages.length == 0 && text){
var else_block = var else_block =
(text ?? []) (text ?? [])
.filter(function(e){ .filter(function(e){
return typeof(e) != 'string' return typeof(e) != 'string'
&& e.name == 'else' }) && e.name == 'else' })
if(else_block.length == 0){ if(else_block.length == 0){
return } return }
// XXX do we take the first or the last (now) block??? // XXX do we take the first or the last (now) block???
else_block = else_block.pop() else_block = else_block.pop()
else_block = else_block =
else_block.args.text else_block.args.text
?? else_block.body ?? else_block.body
return else_block ? return else_block ?
[...this.__parser__.expand(this, else_block, state)] [...this.__parser__.expand(this, else_block, state)]
: undefined } : undefined }
// sort pages... // sort pages...
if(sort.length > 0){ if(sort.length > 0){
// XXX // XXX
throw new Error('macro sort: not implemented') throw new Error('macro sort: not implemented')
} }
// apply macro text... // apply macro text...
// XXX not sure we should expand the whole thing directly here... // XXX not sure we should expand the whole thing directly here...
return pages return pages
.map(function(page){ .map(function(page){
return [...that.__parser__.expand(page, text, state)] }) return [...that.__parser__.expand(page, text, state)] })
.flat() .flat() } }),
} },
// nesting rules... // nesting rules...
'else': ['macro'], 'else': ['macro'],
@ -1834,51 +1851,6 @@ module.pwiki =
Page('/', '/', store) Page('/', '/', store)
// XXX should we also convert values??
// ...like:
// "true" -> true
// "123" -> 123
// ...
var parseArgs = function(spec, args){
// spec...
var order = spec.slice()
var bools = new Set(
order[order.length-1] instanceof Array ?
order.pop()
: [])
order = order
.filter(function(k){
return !(k in args) })
var res = {}
var pos = Object.entries(args)
// stage 1: populate res with explicit data and place the rest in pos...
.reduce(function(pos, [key, value]){
/^[0-9]+$/.test(key) ?
(bools.has(value) ?
// bool...
(res[value] = true)
// positional...
: (pos[key*1] = value))
// keyword...
: (res[key] = value)
return pos }, [])
// stage 2: populate implicit values from pos...
.forEach(function(e, i){
order.length == 0 ?
(res[e] = true)
: (res[order.shift()] = e) })
return res }
console.log('---',
parseArgs(
['src', 'bam', ['first', 'second']],
{1: 'first', 2: '..', src2: 'second', moo: 'third'}))
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// XXX experiments and testing... // XXX experiments and testing...