-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3fa3dcd
commit 9da599a
Showing
22 changed files
with
688 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Auto detect text files and perform LF normalization | ||
* text=auto |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# Simple workflow for deploying static content to GitHub Pages | ||
name: Deploy static content to Pages | ||
|
||
on: | ||
# Runs on pushes targeting the default branch | ||
push: | ||
branches: ["main"] | ||
|
||
# Allows you to run this workflow manually from the Actions tab | ||
workflow_dispatch: | ||
|
||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages | ||
permissions: | ||
contents: read | ||
pages: write | ||
id-token: write | ||
|
||
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. | ||
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. | ||
concurrency: | ||
group: "pages" | ||
cancel-in-progress: false | ||
|
||
jobs: | ||
# Single deploy job since we're just deploying | ||
deploy: | ||
environment: | ||
name: github-pages | ||
url: ${{ steps.deployment.outputs.page_url }} | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
- name: Setup Pages | ||
uses: actions/configure-pages@v4 | ||
- name: Use Node.js | ||
uses: actions/setup-node@v2 | ||
with: | ||
node-version: '20.x' # replace with your Node.js version | ||
- name: Install Dependencies | ||
run: npm ci | ||
- name: Validating Project | ||
run: npm run build | ||
- name: Upload artifact | ||
uses: actions/upload-pages-artifact@v3 | ||
with: | ||
# Upload entire repository | ||
path: './public' | ||
- name: Deploy to GitHub Pages | ||
id: deployment | ||
uses: actions/deploy-pages@v4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
/node_modules/* | ||
/public/* | ||
!/public/main.css |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
export function Path2Name(path: string) { | ||
let startIndex = path.lastIndexOf("/"); | ||
if (startIndex !== 0 || path[0] !== "/") startIndex++; | ||
|
||
let endIndex = path.indexOf(".", startIndex); | ||
if (endIndex === -1) endIndex = path.length; | ||
|
||
const filename = path | ||
.slice(startIndex, endIndex) | ||
.replaceAll("-", " "); | ||
|
||
return filename; | ||
} | ||
|
||
export function Reroute(path: string) { | ||
let endIndex = path.lastIndexOf("."); | ||
if (endIndex === 0) endIndex = path.length; | ||
|
||
return `/${path.startsWith("./docs") | ||
? path.slice(7, endIndex) | ||
: path | ||
}`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { CreateFolderPage, CreatePage } from "./page"; | ||
import { readdir, stat, mkdir } from "fs/promises"; | ||
import { CreateToolbar } from "./toolbar"; | ||
|
||
console.info("Building Docs..."); | ||
|
||
|
||
async function GroupPaths (paths: string[]) { | ||
const stats = await Promise.all(paths.map( x => stat(x))); | ||
|
||
return { | ||
folders: paths.filter((_, i) => !stats[i].isFile()), | ||
files: paths.filter((_, i) => stats[i].isFile()) | ||
} | ||
} | ||
|
||
async function BuildDir(path: string) { | ||
const paths = await readdir(path); | ||
|
||
|
||
for (let i=0; i<paths.length; i++) { | ||
paths[i] = `${path}/${paths[i]}`; | ||
} | ||
|
||
if (path !== "./docs") await mkdir(`./public/${path.slice(7)}`, { recursive: true }); | ||
|
||
const { files, folders } = await GroupPaths(paths); | ||
const toolbar = CreateToolbar(path, folders, files); | ||
await Promise.all(files.map(f => CreatePage(toolbar, f))); | ||
await CreateFolderPage(toolbar, path); | ||
|
||
await Promise.all(folders.map(BuildDir)); | ||
} | ||
|
||
|
||
BuildDir("./docs"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
import { readFile, writeFile } from "fs/promises"; | ||
import { Path2Name, Reroute } from "./helper"; | ||
|
||
export async function CreatePage(toolbar: string, path: string) { | ||
const extIndex = path.lastIndexOf("."); | ||
const ext = path.slice(extIndex); | ||
if (ext != ".md") return; | ||
|
||
const data = await readFile(path, "utf8"); | ||
const { html, type } = RenderPage(path, data); | ||
|
||
const document = `<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>${Path2Name(path)}</title> | ||
<link rel="stylesheet" href="/main.css"/> | ||
<script src="/index.js"></script> | ||
</head> | ||
<body> | ||
${toolbar} | ||
<div class="dashboard"> | ||
<details class="entry" data-src="${Reroute(path)}">${html}</details> | ||
</div> | ||
</body> | ||
</html>`; | ||
|
||
writeFile(`./public/${path.slice(7, extIndex)}.html`, document); | ||
|
||
return type; | ||
} | ||
|
||
|
||
export async function CreateFolderPage(toolbar: string, path: string) { | ||
const html = `<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>${Path2Name(path)}</title> | ||
<link rel="stylesheet" href="/main.css"/> | ||
<script src="/index.js"></script> | ||
</head> | ||
<body> | ||
${toolbar} | ||
<div class="dashboard"></div> | ||
</body> | ||
</html>`; | ||
|
||
writeFile(`./public/${path.slice(7) || "index"}.html`, html); | ||
} | ||
|
||
|
||
|
||
function RenderPage(path: string, data: string) { | ||
const pathFrag = path.split("/"); | ||
const { summary, details } = IngestPage(data); | ||
|
||
const html = `<summary>` | ||
+ `<span class="comment">${pathFrag.slice(2, -1).join("/")}</span>` | ||
+ `<div>` | ||
+ `<div class="signature">` | ||
+ `<span class="name">${Path2Name(pathFrag[pathFrag.length-1])}</span> ` | ||
+ (summary.type == "structure" ? "{" : "(") | ||
+ `<div class="cluster">` | ||
+ summary.params.map(p => `<div class="indent">` | ||
+`<span class="argument">${p.name}</span>` | ||
+`: ${p.type}` | ||
+ `<span class="comment" style="margin-left: 1em;">${p.description}</span>` | ||
+`</div>`).join("") | ||
+ `</div>` | ||
+ (summary.type == "function" | ||
? ("): " | ||
+ `<div style="display: inline-block;">${summary.returns.map(p => `<div>` | ||
+`<span class="argument">${p.name}</span>` | ||
+`: ${p.type}` | ||
+ `<span class="comment" style="margin-left: 1em;"> ${p.description}</span>` | ||
+`</div>`).join("")}</div>` | ||
) : "}") | ||
+ `</div>` | ||
+ `</div>` | ||
+ `<div class="close" onclick="this.parentNode.parentNode.remove();">Close</div>` | ||
+ `<div style="white-space: pre-wrap;">${summary.text}</div>` | ||
+ `</summary>` | ||
+ `<div style="white-space: pre-wrap;">${details}</div>`; | ||
|
||
return { html, type: summary.type }; | ||
} | ||
|
||
|
||
type TypeDefMap = Map<string, string>; | ||
function IngestPage(data: string) { | ||
const [primary, ...secondary] = data.split(`\n---\n`); | ||
|
||
let definitions = new Map<string, string>(); | ||
let type = "function"; | ||
let summary = ""; | ||
let params = new Array<ReturnType<typeof ProcessSignatureLine>>(); | ||
let returns = new Array<ReturnType<typeof ProcessSignatureLine>>(); | ||
for (const line of primary.split("\n")) { | ||
if (line[0] !== "@") { | ||
summary += "\n" + line; | ||
continue; | ||
} | ||
|
||
const [key, rest] = SplitString(line, " "); | ||
switch (key) { | ||
case "@param": { | ||
params.push(ProcessSignatureLine(definitions, rest)); | ||
break; | ||
} | ||
case "@return" : { | ||
returns.push(ProcessSignatureLine(definitions, rest)); | ||
break; | ||
} | ||
case "@typedef" : { | ||
IngestTypedef(definitions, rest); | ||
break; | ||
} | ||
case "@function": { | ||
type = "function"; | ||
break; | ||
} | ||
case "@structure": { | ||
type = "structure"; | ||
break; | ||
} | ||
default: | ||
console.error(`Unknown key ${key}`); | ||
summary += `\n${key} ${rest}`; | ||
} | ||
} | ||
|
||
return { | ||
summary: { | ||
type, | ||
params, returns, | ||
text: summary | ||
}, | ||
details: secondary | ||
} | ||
} | ||
|
||
|
||
function SplitString(str: string, pivot: string) { | ||
let index = str.indexOf(pivot); | ||
if (index === -1) index = str.length; | ||
|
||
return [ str.slice(0, index), str.slice(index+pivot.length) ]; | ||
} | ||
|
||
function ProcessSignatureLine(ctx: TypeDefMap, line: string) { | ||
const [ name, line1 ] = SplitString(line, ": "); | ||
const [ typeStr, description ] = SplitString(line1, " - "); | ||
|
||
const type = ctx.has(typeStr) | ||
? `<a class="type" href="${ctx.get(typeStr)}" entry>${typeStr}</a>` | ||
: `<span class="type">${typeStr}</span>`; | ||
|
||
return { name, type, description } | ||
} | ||
|
||
function IngestTypedef(ctx: TypeDefMap, line: string) { | ||
const [ type, href ] = SplitString(line, " "); | ||
ctx.set(type, href); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { Path2Name, Reroute } from "./helper"; | ||
|
||
export function CreateToolbar(href: string, folders: string[], files: string[]) { | ||
|
||
const pathFrags = href.split("/").slice(2); // ignore ./docs | ||
const parents = pathFrags.map((x, i) => i == 0 | ||
? { | ||
name: Path2Name(x), | ||
path: `/${x}`, | ||
} : { | ||
name: Path2Name(x), | ||
path: `/${pathFrags[i-1]}/${x}`, | ||
} | ||
); | ||
|
||
return `<div class="toolbar" style="display: flex; flex-direction: column;"> | ||
${href !== "./docs" ? `<a href="/" parent folder> Index</a>` : ""} | ||
${parents.map(x => | ||
`<a href="${x.path}" parent folder> | ||
${x.name} | ||
</a>`).join("\n\t")} | ||
${folders.map(x => | ||
`<a href="${Reroute(x)}" folder> | ||
${Path2Name(x)} | ||
</a>`).join("\n\t")} | ||
${files.map(x => | ||
`<a href="${Reroute(x)}" entry> | ||
${Path2Name(x)} | ||
</a>`).join("\n\t")} | ||
</div>`; | ||
} |
Oops, something went wrong.