From e3246c7fb247bdfbd011d2125c68ef3cc7797d55 Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Wed, 17 Aug 2022 23:38:24 +0300 Subject: [PATCH] cleanup and tweaking... Signed-off-by: Alex A. Naanou --- pwiki/page.js | 163 +++++++++++++++++++++++++------------------- pwiki/parser.js | 56 ++++++++------- pwiki/store/base.js | 2 +- pwiki2-test.js | 16 ++++- pwiki2.js | 24 ++----- 5 files changed, 144 insertions(+), 117 deletions(-) diff --git a/pwiki/page.js b/pwiki/page.js index f7306f4..dc8e6e3 100755 --- a/pwiki/page.js +++ b/pwiki/page.js @@ -505,7 +505,7 @@ object.Constructor('Page', BasePage, { QUOTING_MACROS: ['quote'], // templates used to render a page via .text - PAGE_TEMPLATE: '_text', + PAGE_TEMPLATE: '_view', // NOTE: comment this out to make the system fail when nothing is // resolved, not even the System/NotFound page... @@ -658,6 +658,7 @@ object.Constructor('Page', BasePage, { // the context, this potentially can lead to false positives. // // XXX should this be lazy??? + // XXX should we use .__parser__.expand(..) instead of .parse(..) ??? include: Macro( ['src', 'recursive', 'join', ['isolated']], async function(args, body, state, key='included', handler){ @@ -758,6 +759,7 @@ object.Constructor('Page', BasePage, { // XXX need to handle pattern paths (like include: join=...) // XXX need a way to escape macros -- i.e. include in a quoted text... quote: Macro( + //['src', 'filter', 'text', 'join'], ['src', 'filter', 'text'], async function(args, body, state){ var src = args.src //|| args[0] @@ -866,12 +868,18 @@ object.Constructor('Page', BasePage, { // show first instance... : name in slots) - slots[name] = [...await this.__parser__.expand(this, text, state)] + // NOTE: we prioritize the nested slots over the current... + delete slots[name] + var slot = await this.__parser__.expand(this, text, state) + slots[name] = + slots[name] + ?? slot return hidden ? '' : function(state){ return state.slots[name] } }), + 'slot-content': ['slot'], // // > .. @@ -969,7 +977,7 @@ object.Constructor('Page', BasePage, { && (text || args['else'])){ var else_block = _getBlock('else') return else_block ? - [...await this.__parser__.expand(this, else_block, state)] + await this.__parser__.expand(this, else_block, state) : undefined } // sort pages... @@ -980,15 +988,13 @@ object.Constructor('Page', BasePage, { var join_block = _getBlock('join') // apply macro text... - var res = await pages - .map(function(page, i){ + var res = pages + .map(function(page){ return that.__parser__.expand(page, text, state) }) return join_block ? - res.between(await that.__parser__.expand( + res.between( // render join block relative to the path before the first '*'... - that.get(that.path.split(/\*/).shift()), - join_block, - state)) + await that.__parser__.expand(base, join_block, state)) : res } }), // nesting rules... @@ -1200,10 +1206,10 @@ module.System = { // These are used to control how a page is rendered. // // pWiki has to have a template appended to any path, if one is not - // given then "_text" is used internally. + // given then "_view" is used internally. // // A template is rendered in the context of the parent page, e.g. - // for /path/to/page, the actual rendered template is /path/to/page/_text + // for /path/to/page, the actual rendered template is /path/to/page/_view // and it is rendered from /path/to/page. // // A template is any page named starting with an underscore ("_") @@ -1217,10 +1223,10 @@ module.System = { // // XXX all of these should support pattern pages... _text: { - //text: '@include(. isolated join="@source(file-separator)")' }, - // XXX problem: the show slot + text: '@include(. isolated join="@source(file-separator)")' }, + _view: { text: object.doc` - @source(./path)/_edit + /list @source(./path)/_edit

@@ -1239,7 +1245,22 @@ module.System = { '' +'
' +'
'}, - // XXX can we reuse _text here??? + /* XXX can we reuse _view here??? + _edit: { + text: + '@include(PageTemplate)' + +'@source(./path)' + +'' + +'' + +'
'
+						+''
+					+'
' + +'
' + +'
'}, + /*/ _edit: { text: '@source(./path)' @@ -1252,13 +1273,30 @@ module.System = { +'' +'' +''}, + //*/ + edit: { + text: + //'@include(PageTemplate)' + '@include(_view)' + +'@source(../path)' + +'' + // XXX for some reason this is not called... + +'' + +'
'
+						+''
+					+'
' + +'
' + +'
'}, // XXX this does not yet work... // XXX "_test" breaks differently than "test" //_test: { test: { text: object.doc` - @source(_text) + @source(_view) HEADER CONTENT FOOTER `}, @@ -1269,68 +1307,41 @@ module.System = { list: { - text: `@source(.)` }, + text: object.doc` + + /list + + @source(../path) + + + + @source(./name) + × + ` }, // XXX this is really slow... - // XXX for some reason replacing both @quote(..) with @source(..) in - // the links will break macro parsing... - // XXX should this be all or tree??? tree: { text: object.doc`
- @source(./name) - × + @source(./name) + ×
@source(./tree)
` }, - - // XXX this is somewhat broken... + all: { + text: `@include(../**/path join="
")`}, info: { text: object.doc` - # @source(./path) - - - Render root: @source(./renderer) - - Render root: @source(./renderer) - - ` }, - - // XXX tests... - // - test_page: function(){ - console.log('--- RENDERER:', this.render_root) - console.log('--- PATH: ', this.path) - console.log('--- REFERRER:', this.referrer) - console.log('--- PAGE:', this) - return this.path }, - test_list: function(){ - return 'abcdef'.split('') }, - // XXX problem: it appears that we can't fill a slot from within a slot... - // ...the "content" slot below does not override the content slot in _text - test_base_slots: { - text: object.doc`OUTER - HEADER - CONTENT - FOOTER `}, - // XXX does not work yet... - test_slots: { - text: object.doc` - Sequential: - unfilled - filled - refilled -

- Nested: - - unfilled - - filled - - refilled - - - ` }, + Path: @source(../path)
+ Resolved path: @source(../resolved)
+ Referrer: @source(../referrer)
+ Renderer: @source(../renderer)
+ ctime: @source(../ctime)
+ mtime: @source(../mtime)
+
+
` }, // page parts... // @@ -1348,15 +1359,24 @@ module.System = { DeletingPage: { text: 'Deleting: @source(../path)' }, + PageTemplate: { + text: object.doc` + @source(./path)/_edit +
+ +
+ ` }, + // page actions... // - // metadata... // renderer: function(){ return (this.render_root || {}).path }, + referrer: function(){ + return this.referrer || this.path }, path: function(){ return this.get('..').path }, location: function(){ @@ -1366,9 +1386,9 @@ module.System = { name: function(){ return this.get('..').name }, ctime: function(){ - return this.get('..').data.ctime }, + return this.get('..').data.ctime ?? '' }, mtime: function(){ - return this.get('..').data.mtime }, + return this.get('..').data.mtime ?? '' }, // XXX this can be a list for pattern paths... resolved: function(){ @@ -1412,6 +1432,11 @@ module.System = { // XXX System/forward // XXX System/sort // XXX System/reverse + + + // XXX broken... + test_list: function(){ + return 'abcdef'.split('') }, } var Settings = diff --git a/pwiki/parser.js b/pwiki/parser.js index 55942ff..8e6ddc0 100755 --- a/pwiki/parser.js +++ b/pwiki/parser.js @@ -387,18 +387,13 @@ module.BaseParser = { // Expand macros... // + // ::= [ , .. ] // ::= - // - // // returned by .macros.filter(..) - // | { - // // XXX is this still relevant... - // filters: [ - // '' - // | '-', - // ... - // ], - // data: [ , .. ], - // } + // + // | + // | + // | { data: } + // | // // XXX macros: we are mixing up ast state and parse state... // one should only be used for parsing and be forgotten after @@ -440,13 +435,37 @@ module.BaseParser = { } else { yield res } } }, + // recursively resolve and enumerate the ast... + // + // ::= [ , .. ] + // ::= + // + // | { data: } + // + // XXX should this also resolve e.data??? + resolve: async function*(page, ast, state={}){ + // NOTE: we need to await for ast here as we need stage 2 of + // parsing to happen AFTER everything else completes... + for(var e of await ast){ + e = typeof(e) == 'function' ? + e.call(page, state) + : e + + if(e instanceof Array){ + yield* this.resolve(page, e, state) + } else if(e instanceof Object && 'data' in e){ + yield { data: await this.resolve(page, e.data, state) } + } else { + yield e } } }, + // Fully parse a page... // // This runs in two stages: - // - expand the page + // - resolve the page // - lex the page -- .lex(..) // - group block elements -- .group(..) // - expand macros -- .expand(..) + // - resolve ast -- .resolve(..) // - apply filters // // NOTE: this has to synchronize everything between stage 1 (up to @@ -458,7 +477,6 @@ module.BaseParser = { // them on demand rather than on encounter (as is now), e.g. // a slot when loaded will replace the prior occurrences... // - // XXX this should be recursive.... // XXX add a special filter to clear pending filters... (???) parse: async function(page, ast, state={}){ var that = this @@ -468,17 +486,7 @@ module.BaseParser = { this.expand(page, ast, state) : ast - // NOTE: we need to await for ast here as we need stage 2 of - // parsing to happen AFTER everything else completes... - return await Promise.iter((await ast) - .flat() - // post handlers... - .map(function(section){ - return typeof(section) == 'function' ? - // NOTE: this can produce promises... - section.call(page, state) - : section })) - .flat() + return await this.resolve(page, ast, state) // filters... .map(function(section){ return ( diff --git a/pwiki/store/base.js b/pwiki/store/base.js index 9944891..58e7990 100755 --- a/pwiki/store/base.js +++ b/pwiki/store/base.js @@ -165,7 +165,7 @@ module.BaseStore = { .replace(/^\/|\/$/g, '') .replace(/\//g, '\\/') .replace(/\*\*/g, '.*') - .replace(/\*/g, '[^\\/]*') + .replace(/(?<=^|[\\\/]+|[^.])\*/g, '[^\\/]*') }(?=[\\\\\/]|$)`) return [...(await this.paths()) // NOTE: we are not using .filter(..) here as wee diff --git a/pwiki2-test.js b/pwiki2-test.js index 82c6923..f383afa 100755 --- a/pwiki2-test.js +++ b/pwiki2-test.js @@ -179,11 +179,9 @@ pwiki.pwiki text: object.doc` Sequential: unfilled - filled - refilled - +

Nested: unfilled @@ -194,6 +192,18 @@ pwiki.pwiki `, }) + .update({ + location: '/test/nesting', + text: object.doc` + Quote in macro: + + + +
+ Quote in slot: + + + ` }) .update({ location: '/test/a', text: 'a', diff --git a/pwiki2.js b/pwiki2.js index 70274a6..5638bb2 100755 --- a/pwiki2.js +++ b/pwiki2.js @@ -1,33 +1,17 @@ /********************************************************************** * * -* XXX nested slots do not seem to work... -* XXX BUG: /** /paths -- does not work... +* XXX might be a good idea for slots to support getting previous slot +* content, e.g.: +* new text * XXX BUG?: markdown: when parsing chunks each chunk gets an open/closed *

inserted at start/end -- this breaks stuff returned by macros... * ...there are two ways to dance around this: * - make filters run a bit more globaly -- per block... * - find a local parser... -* XXX BUG?: empty stores do not appear to show up in listings... -* ...this is expected but not intuitive... -* might be a good idea to add a special path like /Stores to list -* sub-stores... +* XXX add something like /stores to list store info... * XXX OPTIMIZE: /tree is really slow... * ...is the problem purely in the async/await playing ping-pong??? -* XXX might be a good idea to make things optionally sync via a .sync() -* method, or request a specific set of data (in the parser, after -* collecting all the stuff needed and fetching it in one go)... -* XXX might be a good idea to add page caching (state.page_cache) relative -* to a path on parsing, to avoid re-matching the same page over and -* over again from the same context -* format: -* { -* : { -* : , -* ... -* }, -* ... -* } * XXX BUG: FF: conflict between object.run and PouchDB... * XXX BUG: browser: .get('/*').raw hangs in the browser context... * XXX BUG?: /_tree for some reason does not show anything on lower levels...