X-Git-Url: https://dreyeck.freedombox.rocks/gitweb/idiomatic.git/blobdiff_plain/96f9e23cc6e9201f27fb656588199e234901420e..291e0dae80776eed417ab084896e7fa2390d5387:/index.js
diff --git a/index.js b/index.js
index b3334a5..9f1a2b7 100644
--- a/index.js
+++ b/index.js
@@ -1,33 +1,15 @@
-let express = require('express')
-let acorn = require('acorn')
-let fs = require('fs')
-// let fs = require('node:fs/promises');
+const express = require('express')
+const acorn = require('acorn')
+const fs = require('fs')
+const visitor = require('./visitor.js')
-let visitor = require('./visitor.js')
-let dir = '../wiki-client/lib'
-let mods = []
-const app = express()
-
-
-// P A G E S
+// P A R S E
-app.get('/index', async (req,res,next) => {
- console.log(new Date().toLocaleTimeString(), 'index')
- const reductions = counter()
- fs.readdir(dir, async (err, files) => {
- mods = await Promise.all(files.map(load))
- const doit = branch => {reductions.count(branch.type)}
- visitor.wander(mods,doit)
- const result = `
-
${reductions.size()} non-terminals
-
${reductions.total()} reductions
-
${reductions.tally()
- .map(([k,v]) => `${v} ${link(k)}`)
- .join("
")}`
- res.send(result);
- next()
- })
+const dir = '../wiki-client/lib'
+const mods = []
+fs.readdir(dir, async (err, files) => {
+ mods.push(... await Promise.all(files.map(load)))
})
async function load(file) {
@@ -39,44 +21,113 @@ async function load(file) {
})
}
-function link(key) {
- if(key.match(/^Ident/)) return `${key}`
- if(key.match(/^(As|B|L|U).*Ex/)) return `${key}`
- if(key.match(/^Lit/)) return `${key}`
- return key
-}
+// P A G E S
-app.get('/terminal', (req,res) => {
- const lits = counter()
- const id = req.query.type
- const field = req.query.field
- const doit = branch => {if(branch.type==id) lits.count(branch[field])}
- visitor.wander(mods,doit)
+const style = (title,here='') => `
+
+ `
+const app = express()
+
+app.get('/index', async (req,res) => {
+ const reductions = counter()
+ visitor.walk(mods,branch =>
+ reductions.count(branch.type))
const result = `
-
${lits.size()} uniques
-
${lits.total()} total
-
${lits.tally()
- .map(([k,v]) => `${v} ${escape(k)}`)
- .join("
")}`
+
${reductions.size()} non-terminals
+
${reductions.total()} reductions
+
${reductions.tally()
+ .map(([k,v]) => `| ${v} | ${link(k)}`)
+ .join("\n")} |
`
+ res.send(style('index')+result);
+
+ function link(key) {
+ if(key.match(/^Ident/)) return `${key}`
+ if(key.match(/^(As|B|L|U).*Ex/)) return `${key}`
+ if(key.match(/^Lit/)) return `${key}`
+ return key
+ }
+})
+
+app.get('/terminal', (req,res) => {
+ const {type,field} = req.query
+ const terms = counter()
+ visitor.walk(mods,branch => {
+ if(branch.type==type)
+ terms.count(branch[field])})
+ const result = style('terminal',type)+`
+ ${terms.size()} uniques
+
${terms.total()} total
+
${terms.tally()
+ .map(([k,v]) => `| ${v} | ${escape(k)}`)
+ .join("\n")} |
`
res.send(result)
})
app.get('/usage', (req,res) => {
- const type = req.query.type
- const field = req.query.field
- const key = req.query.key
+ const {type,field,key,width,depth} = req.query
const list = []
- const doit = (branch,stack) => {
- if(branch.type==type && branch[field]==key)
- list.push(`${stack.at(-1)} ${sxpr(stack[2],3)}`
- // `${stack.length}
- // ${stack.at(-1)}-${branch.start}-${branch.end}
- // (${stack.slice(0,6).map(n => n.end-n.start).join(" ")})`
- )
- }
- visitor.wander(mods,doit)
- res.send(`${JSON.stringify(req.query,null,2)}${list.join("
")}`)
+ const files = counter()
+ visitor.walk(mods,(branch,stack) => {
+ if(branch.type==type && branch[field]==key)list.push(`
+ |
+ ${stack.at(-1)}
+ | ${sxpr(stack[width ?? 2], depth ?? 3)}`)})
+ list.sort((a,b) => vis(a)>vis(b) ? 1 : -1)
+ const q = (id,delta) => Object.entries(req.query)
+ .map(([k,v]) => k == id ? `${k}=${+v+delta}` : `${k}=${v}`)
+ .join('&')
+ const p = id => ` + `
+ const m = id => ` − `
+ const d = id => `${id} ${p(id)} ${m(id)}`
+ res.send(style('usage',key)+`
+ ${files.total()} uses in ${files.size()} files
+ ${files.tally().map(([k,v]) => `| ${v} | ${k}`).join("\n")} |
+
${d('width')} ${d('depth')}
+ `)
+})
+
+app.get('/nesting', (req,res) => {
+ const {file,type,key,start,end} = req.query
+ const result = []
+ visitor.walk(mods,(branch,stack) => {
+ if(stack.at(-1)==file && branch.type==type && branch.start==start && branch.end==end) {
+ const path = stack.slice(0,-1).map((n,i) => `
+ |
+ | ${n.type}:
+ | ${sxpr(n,3,null,stack[i-1])}`).reverse()
+ const hit = stack[1]
+ result.push(`
+
+ ${escape(JSON.stringify(hit,omit,2))}`)
+ }
+ })
+ res.send(style('nesting',key)+`${result.join(" ")}`)
+})
+
+app.get('/similar', (req,res) => {
+ const {file,type,key,start,end,nest} = req.query
+ let nested
+ visitor.walk(mods,(branch,stack) => {
+ if(stack.at(-1)==file && branch.type==type && branch.start==start && branch.end==end)
+ nested = stack[nest]})
+ const norm = node => vis(`\n\n\n${sxpr(node,3,null)}`)
+ const source = (file,node) => mods.find(mod => mod.file == file).text.substring(+node.start,+node.end)
+ const want = norm(nested)
+ const result = []
+ visitor.walk(mods,(branch,stack) => {
+ if(norm(branch) == want)
+ result.push(`${escape(source(stack.at(-1),branch))} `)})
+ res.send(style('similar',key)+
+ `${want} ` +
+ result.join("\n")
+ )
})
@@ -90,6 +141,7 @@ function counter() {
counts.set(item, counts.get(item)+1)
else
counts.set(item,1)
+ return item
},
size() {
return counts.size
@@ -119,14 +171,14 @@ function escape(text) {
function sxpr(obj,deep,key,child) {
const hilite = obj===child ? 'class="hi"' : ''
- const link = word => obj.type == 'Identifier' ? `${word}` : word
+ const link = word => obj.type == 'Identifier' ? `${word}` : word
if (obj) {
if(deep) {
const fields = Object.entries(obj)
.filter(([k,v]) => !['start','end','raw','computed','optional','kind'].includes(k))
.map(([k,v]) =>
k=='type' ? abv(v) :
- (typeof v == 'string') ? link(expand(v)) :
+ (typeof v == 'string') ? link(escape(v)) :
Array.isArray(v) ? `[${v.map(o => sxpr(o,deep-1,k,child)).join(" ")}]` :
sxpr(v, deep-1, k, child))
.join(" ")
@@ -149,12 +201,16 @@ function elipsis(obj) {
return `(${dots})`
}
-function expand(text) {
- return text
- .replace(/&/g, '&')
- .replace(//g, '>')
- .replace(/\*(.+?)\*/g, '$1')
-};
+function vis(row) {
+ return row.split(/\n/)[3].trim()
+ .replaceAll(/<.*?>/g,'')
+ .replaceAll(/\.\.+/g,'..')
+}
+
+function query(obj,adj={}) {
+ return Object.entries(obj)
+ .map(([k,v]) => k in adj ? `${k}=${adj[k](v)}` : `${k}=${v}`)
+ .join('&')
+}
app.listen(1954)
\ No newline at end of file
|