What's New in Wiki

I was recently reconnecting with an old friend and occasional business associate from the Smalltalk-80 days. Here I excerpt from that letter and now will test the code.

Federated wiki is now 15 years old, half of wiki’s 30 years. These dates have become markers in my own history. When I read of enhancements in, say, cosmology, I think, in which wiki era was that discovery made?

The newer wiki continues its linear growth in sites and pages. We continually find new things to do with the mass of JSON we have accumulated. A year or two ago we turned away from writing html scripts run from asset directories only loosely associated with pages.

The new scheme, called Mech, is loosely modeled on the “block” languages like Scratch, sans the graphical editor. Our first block was HELLO, which would emit a smilie when run. Our second block CLICK would run the blocks nested underneath when clicked.

CLICK HELLO

We make up for the absence of a graphic editor with in-place clickable errors and trace. Substantial results can be offered as new pages in the lineup to be read, copied from, or forked to become part of one’s own wiki.

ward.fed.wiki found.ward.fed.wiki ward.dojo.fed.wiki next.ward.dojo.fed.wiki

A typical use would be to grab some data from the neighborhood, transform it in some useful way, and then present a new page that may or may not be worth keeping. Our newest block, CODE, will find some fragment of JavaScript on the page and run that in the context we establish for any block.

CLICK NEIGHBORS fed.wiki CODE popular 15 CLICK PREVIEW items

One could then code on the same page an item that implements the transformation with access to the Mech state through “this” bound to a selective proxy that includes our tracing mechanisms so that the ins and outs have automatic visibility.

export function popular(count) {
  let tally = this.neighborhood.reduce( … )
  let top = tally.sort.slice(0,count)
  this.items = top.map( … )
}

.

Here I replace some elided code with function names.

export function popular(count) { globalThis = this let infos = this.neighborhood let tally = infos.reduce(links, []) let top = tally.sort(desc).slice(0,count) this.items = top.map(report) return `${tally.length} linked pages` }

Add the outbound links of each page to a bag of slugs.

function links(sum, each) { return Bag.addAll(sum, each.links) }

Sort Bag entries by descending reference count.

function desc(a,b) { return b[1] - a[1] }

Convert a Bag entry to wiki markup. This once just showed slug and count but is much improved by referring these back to sitemap entries.

function report([slug,count]) { let info = globalThis.neighborhood .find(info => info.slug == slug) if(!info) return `${slug} (${count})` return { type:'reference', site:info.domain, slug:info.slug, title:info.title, text:`${info.synopsis} (${count})` }}

We wish javascript had a Bag abstraction, which we often call tally in our own work. Here we define just enough of Bag to make this Mech work.

class Bag { static addAll(entries,links) { let slugs = [...Object.keys(links||{})] slugs.forEach(slug => { let here = entries.find(entry => entry[0] == slug) if(here) here[1] += 1 else entries.push([slug,1]) }) return entries } }

We've resisted some simplifications in order to follow the sequence suggested in my email. This is especially true with respect to our use here of "globalThis". mdn