Added support for static doctest files generated by the iwmsite static site generator.
This commit is contained in:
parent
0cff31e65b
commit
13e0473328
4
.gitignore
vendored
4
.gitignore
vendored
@ -83,4 +83,6 @@ typings/
|
|||||||
# ignore generated contents-
|
# ignore generated contents-
|
||||||
/doc/out/*
|
/doc/out/*
|
||||||
**/thumbnails
|
**/thumbnails
|
||||||
**/thumbnail.png
|
**/thumbnail.png
|
||||||
|
/site/dist
|
||||||
|
/site/__pycache__
|
249
doc/ast.html
249
doc/ast.html
@ -1,30 +1,28 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<style>
|
<style>
|
||||||
|
.node circle {
|
||||||
|
fill: #999;
|
||||||
|
}
|
||||||
|
|
||||||
.node circle {
|
.node text {
|
||||||
fill: #999;
|
font: 10px sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
.node text {
|
.node--internal circle {
|
||||||
font: 10px sans-serif;
|
fill: #555;
|
||||||
}
|
}
|
||||||
|
|
||||||
.node--internal circle {
|
.node--internal text {
|
||||||
fill: #555;
|
text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.node--internal text {
|
|
||||||
text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link {
|
|
||||||
fill: none;
|
|
||||||
stroke: #555;
|
|
||||||
stroke-opacity: 0.4;
|
|
||||||
stroke-width: 1.5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
.link {
|
||||||
|
fill: none;
|
||||||
|
stroke: #555;
|
||||||
|
stroke-opacity: 0.4;
|
||||||
|
stroke-width: 1.5px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<svg width="960" height="512"></svg>
|
<svg width="960" height="512"></svg>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
||||||
@ -32,104 +30,106 @@
|
|||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.7.1/d3.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.7.1/d3.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/acorn/4.0.11/acorn.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/acorn/4.0.11/acorn.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
fetch('../apps/loader/js/main.js')
|
||||||
|
.then((response) => response.text())
|
||||||
|
.then((text) => {
|
||||||
|
const ast = acorn.parse(text, {
|
||||||
|
sourceType: 'module',
|
||||||
|
// collect ranges for each node
|
||||||
|
ranges: true,
|
||||||
|
// collect comments in Esprima's format
|
||||||
|
onComment: null,
|
||||||
|
// collect token ranges
|
||||||
|
onToken: null
|
||||||
|
})
|
||||||
|
|
||||||
fetch("../apps/loader/js/main.js")
|
console.info(ast)
|
||||||
.then(response => response.text())
|
|
||||||
.then(text => {
|
|
||||||
const ast = acorn.parse(text, {
|
|
||||||
sourceType: "module",
|
|
||||||
// collect ranges for each node
|
|
||||||
ranges: true,
|
|
||||||
// collect comments in Esprima's format
|
|
||||||
onComment: null,
|
|
||||||
// collect token ranges
|
|
||||||
onToken: null
|
|
||||||
})
|
|
||||||
|
|
||||||
console.info(ast)
|
|
||||||
|
|
||||||
drawAst(ast)
|
drawAst(ast)
|
||||||
})
|
})
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
function drawAst(ast) {
|
function drawAst(ast) {
|
||||||
|
// Create SVG element
|
||||||
// Create SVG element
|
//---------------------------
|
||||||
//---------------------------
|
let svg = d3.select('svg')
|
||||||
let svg = d3.select("svg")
|
const width = svg.attr('width')
|
||||||
const width = svg.attr("width")
|
const height = svg.attr('height')
|
||||||
const height = svg.attr("height")
|
let g = svg.append('g').attr('transform', 'translate(40,0)')
|
||||||
let g = svg.append("g").attr("transform", "translate(40,0)")
|
|
||||||
|
|
||||||
// Convert data
|
|
||||||
//---------------------------
|
|
||||||
const data = acornToHierarchy(ast)
|
|
||||||
|
|
||||||
// Create D3 Hierarchy
|
|
||||||
//---------------------------
|
|
||||||
let root = d3.hierarchy(data).sort((a, b) => {
|
|
||||||
return (a.height - b.height) || a.data.name.localeCompare(b.data.name);
|
|
||||||
})
|
|
||||||
|
|
||||||
// Create D3 Cluster
|
// Convert data
|
||||||
//---------------------------
|
//---------------------------
|
||||||
let tree = d3.cluster().size([height, width - 200])
|
const data = acornToHierarchy(ast)
|
||||||
tree(root)
|
|
||||||
|
|
||||||
// Create SVG elements
|
|
||||||
//---------------------------
|
|
||||||
let link = g.selectAll(".link")
|
|
||||||
.data(root.descendants().slice(1))
|
|
||||||
.enter().append("path")
|
|
||||||
.attr("class", "link")
|
|
||||||
.attr("d", d => {
|
|
||||||
return `M${d.y},${d.x}C${d.parent.y + 100},${d.x} ${d.parent.y + 100},${d.parent.x} ${d.parent.y},${d.parent.x}`
|
|
||||||
})
|
|
||||||
|
|
||||||
let node = g.selectAll(".node")
|
|
||||||
.data(root.descendants())
|
|
||||||
.enter().append("g")
|
|
||||||
.attr("class", d => "node" + (d.children ? " node--internal" : " node--leaf"))
|
|
||||||
.attr("transform", d => `translate(${d.y},${d.x})`)
|
|
||||||
|
|
||||||
node.append("circle")
|
|
||||||
.attr("r", 5)
|
|
||||||
|
|
||||||
node.append("text")
|
|
||||||
.attr("dy", 3)
|
|
||||||
.attr("x", d => d.children ? -8 : 8)
|
|
||||||
.style("text-anchor", d => d.children ? "end" : "start")
|
|
||||||
.text(d => d.data.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
// Create D3 Hierarchy
|
||||||
*
|
//---------------------------
|
||||||
*/
|
let root = d3.hierarchy(data).sort((a, b) => {
|
||||||
function acornToHierarchy(ast) {
|
return a.height - b.height || a.data.name.localeCompare(b.data.name)
|
||||||
|
})
|
||||||
console.info(JSON.stringify(ast))
|
|
||||||
|
// Create D3 Cluster
|
||||||
let data = {}
|
//---------------------------
|
||||||
|
let tree = d3.cluster().size([height, width - 200])
|
||||||
for (const clazz of ast.body) {
|
tree(root)
|
||||||
if (clazz.type === "ClassDeclaration") {
|
|
||||||
data.name = clazz.id.name
|
// Create SVG elements
|
||||||
data.children = []
|
//---------------------------
|
||||||
|
let link = g
|
||||||
for (const method of clazz.body.body) {
|
.selectAll('.link')
|
||||||
if (method.type === "MethodDefinition") {
|
.data(root.descendants().slice(1))
|
||||||
data.children.push({
|
.enter()
|
||||||
name: method.key.name,
|
.append('path')
|
||||||
children: []
|
.attr('class', 'link')
|
||||||
})
|
.attr('d', (d) => {
|
||||||
}
|
return `M${d.y},${d.x}C${d.parent.y + 100},${d.x} ${d.parent.y + 100},${d.parent.x} ${d.parent.y},${
|
||||||
}
|
d.parent.x
|
||||||
}
|
}`
|
||||||
}
|
})
|
||||||
|
|
||||||
/*
|
let node = g
|
||||||
|
.selectAll('.node')
|
||||||
|
.data(root.descendants())
|
||||||
|
.enter()
|
||||||
|
.append('g')
|
||||||
|
.attr('class', (d) => 'node' + (d.children ? ' node--internal' : ' node--leaf'))
|
||||||
|
.attr('transform', (d) => `translate(${d.y},${d.x})`)
|
||||||
|
|
||||||
|
node.append('circle').attr('r', 5)
|
||||||
|
|
||||||
|
node.append('text')
|
||||||
|
.attr('dy', 3)
|
||||||
|
.attr('x', (d) => (d.children ? -8 : 8))
|
||||||
|
.style('text-anchor', (d) => (d.children ? 'end' : 'start'))
|
||||||
|
.text((d) => d.data.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function acornToHierarchy(ast) {
|
||||||
|
console.info(JSON.stringify(ast))
|
||||||
|
|
||||||
|
let data = {}
|
||||||
|
|
||||||
|
for (const clazz of ast.body) {
|
||||||
|
if (clazz.type === 'ClassDeclaration') {
|
||||||
|
data.name = clazz.id.name
|
||||||
|
data.children = []
|
||||||
|
|
||||||
|
for (const method of clazz.body.body) {
|
||||||
|
if (method.type === 'MethodDefinition') {
|
||||||
|
data.children.push({
|
||||||
|
name: method.key.name,
|
||||||
|
children: []
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
const data = {
|
const data = {
|
||||||
"name": "Eve",
|
"name": "Eve",
|
||||||
"children": [{
|
"children": [{
|
||||||
@ -153,22 +153,7 @@ function acornToHierarchy(ast) {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
<title>App</title>
|
||||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css">
|
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css">
|
||||||
<link rel="stylesheet" href="../css/doctest.css">
|
<link rel="stylesheet" href="../css/doctest.css">
|
||||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||||
|
1
site/.python-version
Normal file
1
site/.python-version
Normal file
@ -0,0 +1 @@
|
|||||||
|
3.10.1
|
45
site/main.py
Normal file
45
site/main.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import pathlib
|
||||||
|
from ssg.tags import *
|
||||||
|
from ssg.utils import *
|
||||||
|
from markup import iwmlibdoc_document, sitemap_main
|
||||||
|
|
||||||
|
src = pathlib.Path('..')
|
||||||
|
content = src / 'lib'
|
||||||
|
|
||||||
|
async def main(path:pathlib.Path):
|
||||||
|
"""Typical main program, setting up content publishers, defining the site structure and
|
||||||
|
typical order of generating initial pages and observing subsequent changes.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 2. Build the site structure with nested context managers
|
||||||
|
with site('iwmlibdoc', path=path, doc=iwmlibdoc_document) as docsite:
|
||||||
|
# If we use symlinks the css and image files can be modified without
|
||||||
|
# notifications.
|
||||||
|
docsite.symlink(src, 'css')
|
||||||
|
docsite.symlink(src, 'assets')
|
||||||
|
docsite.symlink(src, 'dist')
|
||||||
|
# structures can be created in a loop to ensure indentical hierarchies
|
||||||
|
|
||||||
|
sitemap = page('sitemap.html',
|
||||||
|
title='Sitemap',
|
||||||
|
main=sitemap_main)
|
||||||
|
static_folder(content)
|
||||||
|
|
||||||
|
# 3. Start generation.
|
||||||
|
docsite.generate()
|
||||||
|
|
||||||
|
#print(docsite)
|
||||||
|
# 4. Let's check whether all links are working...
|
||||||
|
# site.validate()
|
||||||
|
|
||||||
|
await docsite.observe_filesystem(timeout=120)
|
||||||
|
|
||||||
|
def run():
|
||||||
|
default = pathlib.Path('.') / 'dist'
|
||||||
|
if default.exists():
|
||||||
|
shutil.rmtree(default)
|
||||||
|
default.mkdir(parents=True)
|
||||||
|
asyncio.run(main(default))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
run()
|
107
site/markup.py
Normal file
107
site/markup.py
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
|
||||||
|
from typing import Dict, List
|
||||||
|
import ssg.document
|
||||||
|
import ssg.utils
|
||||||
|
from ssg.tags import *
|
||||||
|
from dominate.tags import *
|
||||||
|
|
||||||
|
def iwmlibdoc_document(context):
|
||||||
|
doc = ssg.document.document(title=context.title)
|
||||||
|
with doc.head:
|
||||||
|
meta(charset="utf-8")
|
||||||
|
attr(lang=context.language())
|
||||||
|
if isinstance(context, static_page):
|
||||||
|
for tag in context.soup.find_all('link'):
|
||||||
|
if href := tag.attrs.get('href'):
|
||||||
|
link(rel="stylesheet", href=href)
|
||||||
|
|
||||||
|
for tag in context.soup.find_all('script'):
|
||||||
|
if src := tag.attrs.get('src'):
|
||||||
|
script(src=src)
|
||||||
|
else:
|
||||||
|
link(rel="stylesheet", href= "css/doctest.css")
|
||||||
|
link(rel="stylesheet", href= "css/demo.css")
|
||||||
|
|
||||||
|
with doc.body:
|
||||||
|
site_navigation(context)
|
||||||
|
ssg.document.placeholder(key='main', alternatives=['body']) # here goes the special content part
|
||||||
|
site_footer(context)
|
||||||
|
return doc
|
||||||
|
|
||||||
|
def site_navigation(context):
|
||||||
|
mainmenu(context)
|
||||||
|
br()
|
||||||
|
br()
|
||||||
|
breadcrumb(context)
|
||||||
|
hr()
|
||||||
|
|
||||||
|
|
||||||
|
def level_menu(context, root):
|
||||||
|
for name, child in sorted(context.named_children.items()):
|
||||||
|
if child.folderish():
|
||||||
|
if index := child.named_children.get('index.html'):
|
||||||
|
url = '.' + index.url(relative=root)
|
||||||
|
yield dict(url=url, title=index.title)
|
||||||
|
|
||||||
|
if child.title == name:
|
||||||
|
continue
|
||||||
|
if name.endswith('.html'):
|
||||||
|
url = '.' + child.url(relative=root)
|
||||||
|
yield dict(url=url, title=child.title)
|
||||||
|
|
||||||
|
|
||||||
|
def main_menu(context):
|
||||||
|
root = context.menuroot()
|
||||||
|
if context == root:
|
||||||
|
for info in level_menu(root, root):
|
||||||
|
yield info
|
||||||
|
else:
|
||||||
|
yield dict(url= context.up() + 'sitemap.html', title="Home")
|
||||||
|
for info in level_menu(context.parent, root):
|
||||||
|
yield info
|
||||||
|
|
||||||
|
@nav(cls="breadcrumb")
|
||||||
|
def breadcrumb(context):
|
||||||
|
"""
|
||||||
|
{% macro breadcrumb(context) -%}
|
||||||
|
<nav class="breadcrumb">
|
||||||
|
{% for info in context.breadcrumb() %}
|
||||||
|
{% if info.url %}
|
||||||
|
<a href="{{info.url}}">{{info.title}}</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="#"><u>{{info.title}}</u></a>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</nav>
|
||||||
|
{% endmacro %}
|
||||||
|
"""
|
||||||
|
for info in context.breadcrumb():
|
||||||
|
if url := info.get('url'):
|
||||||
|
a(info['title'], href=url)
|
||||||
|
else:
|
||||||
|
a(info['title'], href='#')
|
||||||
|
|
||||||
|
@nav(cls="mainmenu")
|
||||||
|
def mainmenu(context:ssg.generator):
|
||||||
|
for info in main_menu(context):
|
||||||
|
if url := info.get('url'):
|
||||||
|
a(info['title'], href=url)
|
||||||
|
else:
|
||||||
|
a(info['title'], href='#')
|
||||||
|
|
||||||
|
@main
|
||||||
|
def sitemap_main(context:ssg.generator):
|
||||||
|
root = context.menuroot()
|
||||||
|
h3("Sitemap")
|
||||||
|
with ul(id="sitemap"):
|
||||||
|
for info in getsite().page_infos(relative=root):
|
||||||
|
url = info['url']
|
||||||
|
if url.endswith('.html'):
|
||||||
|
li(a(info['title'], href=url))
|
||||||
|
|
||||||
|
@footer
|
||||||
|
def site_footer(context):
|
||||||
|
hr()
|
||||||
|
date = ssg.utils.now('en')
|
||||||
|
p(f'Generated by IWMSite {date}')
|
||||||
|
|
21
site/requirements.txt
Normal file
21
site/requirements.txt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
aiohttp
|
||||||
|
dominate
|
||||||
|
pytest
|
||||||
|
Babel
|
||||||
|
mypy
|
||||||
|
beautifulsoup4
|
||||||
|
python-socketio
|
||||||
|
requests
|
||||||
|
watchdog
|
||||||
|
|
||||||
|
# streamlit apps
|
||||||
|
streamlit==1.4.0
|
||||||
|
openpyxl
|
||||||
|
plotly
|
||||||
|
fpdf
|
||||||
|
|
||||||
|
# architecture overview
|
||||||
|
diagrams
|
||||||
|
|
||||||
|
# ssg
|
||||||
|
git+ssh://git@gitea.iwm-tuebingen.de/Medienentwicklung/iwmsite.git@master
|
Loading…
Reference in New Issue
Block a user