Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
AjaniBilby committed Apr 14, 2024
1 parent 3fa3dcd commit 9da599a
Show file tree
Hide file tree
Showing 22 changed files with 688 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
51 changes: 51 additions & 0 deletions .github/workflows/static.yml
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/node_modules/*
/public/*
!/public/main.css
23 changes: 23 additions & 0 deletions builder/helper.ts
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
}`;
}
36 changes: 36 additions & 0 deletions builder/index.ts
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");
163 changes: 163 additions & 0 deletions builder/page.ts
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;">&nbsp;${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);
}
33 changes: 33 additions & 0 deletions builder/toolbar.ts
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>`;
}
Loading

0 comments on commit 9da599a

Please sign in to comment.