]>
dreyeck.freedombox.rocks Git - idiomatic.git/blob - index.js
1 let express
= require('express')
2 let acorn
= require('acorn')
4 // let fs = require('node:fs/promises');
6 let visitor
= require('./visitor.js')
7 let dir
= '../wiki-client/lib'
15 app
.get('/index', async (req
,res
,next
) => {
16 console
.log(new Date().toLocaleTimeString(), 'index')
17 const reductions
= counter()
18 fs
.readdir(dir
, async (err
, files
) => {
19 mods
= await Promise
.all(files
.map(load
))
20 const doit
= branch
=> {reductions
.count(branch
.type
)}
21 visitor
.wander(mods
,doit
)
23 <p>${reductions.size()} non-terminals
24 <br>${reductions.total()} reductions
25 <p>${reductions.tally()
26 .map(([k,v]) => `${v} ${link(k)}
`)
33 async
function load(file
) {
34 return new Promise(resolve
=> {
35 fs
.readFile(`${dir}/${file}`, "utf8", (err
,text
) => {
36 const tree
= acorn
.parse(text
, {ecmaVersion
: "latest"})
37 resolve({file
,text
,tree
})
43 if(key
.match(/^Ident/)) return `<a href="/terminal?type=${key}&field=name">${key}</a>`
44 if(key
.match(/^(As|B|L|U).*Ex/)) return `<a href="/terminal?type=${key}&field=operator">${key}</a>`
45 if(key
.match(/^Lit/)) return `<a href="/terminal?type=${key}&field=value">${key}</a>`
50 app
.get('/terminal', (req
,res
) => {
51 const lits
= counter()
52 const id
= req
.query
.type
53 const field
= req
.query
.field
54 const doit
= branch
=> {if(branch
.type
==id
) lits
.count(branch
[field
])}
55 visitor
.wander(mods
,doit
)
57 <p>${lits.size()} uniques
58 <br>${lits.total()} total
60 .map(([k,v]) => `${v}
<a href
="/usage?type=${id}&field=${field}&key=${encodeURIComponent(k)}">${escape(k)}
</a
>`)
65 app
.get('/usage', (req
,res
) => {
66 const type
= req
.query
.type
67 const field
= req
.query
.field
68 const key
= req
.query
.key
70 const doit
= (branch
,stack
) => {
71 if(branch
.type
==type
&& branch
[field
]==key
)
72 list
.push(`${stack.at(-1)} ${sxpr(stack[2],3)}`
74 // ${stack.at(-1)}-${branch.start}-${branch.end}
75 // (${stack.slice(0,6).map(n => n.end-n.start).join(" ")})`
78 visitor
.wander(mods
,doit
)
79 res
.send(`<pre>${JSON.stringify(req.query,null,2)}</pre>${list.join("<br>")}`)
86 const counts
= new Map()
90 counts
.set(item
, counts
.get(item
)+1)
99 .reduce((sum
,each
) => sum
+ each
[1], 0)
103 .sort((a
,b
) => a
[1]==b
[1] ? (a
[0]>b
[0] ? 1 : -1) : b
[1]-a
[1])
108 function escape(text
) {
111 .replace(/&/g
, '&')
112 .replace(/</g
, '<')
113 .replace(/>/g
, '>')
114 .replace(/\*(.+?)\*/g, '<i>$1</i>')
120 function sxpr(obj
,deep
,key
,child
) {
121 const hilite
= obj
===child
? 'class="hi"' : ''
122 const link
= word
=> obj
.type
== 'Identifier' ? `<a href=/context?id=${word}>${word}</a>` : word
125 const fields
= Object
.entries(obj
)
126 .filter(([k
,v
]) => !['start','end','raw','computed','optional','kind'].includes(k
))
129 (typeof v
== 'string') ? link(expand(v
)) :
130 Array
.isArray(v
) ? `[${v.map(o => sxpr(o,deep-1,k,child)).join(" ")}]` :
131 sxpr(v
, deep
-1, k
, child
))
133 return key
? `<span ${hilite} title=${key}>(${(fields)})</span>` : `(${(fields)})`
134 } else return elipsis(obj
)
135 } else return `<span title=${obj}>.</span>`
139 return `<span title=${type}>${type.replaceAll(/[a-z]/g,'')}</span>`
143 return k
=='type'?v
:k
=='start'||k
=='end'?undefined:v
146 function elipsis(obj
) {
147 const bytes
= (obj
.end
||0)-(obj
.start
||0)
148 const dots
= '..' + '.'.repeat(Math
.floor(Math
.log2(bytes
||1)))
149 return `(<span title="${bytes} bytes">${dots}</span>)`
152 function expand(text
) {
154 .replace(/&/g
, '&')
155 .replace(/</g
, '<')
156 .replace(/>/g
, '>')
157 .replace(/\*(.+?)\*/g, '<i>$1</i>')