import { Issue } from "./githubType.ts"; import { copy } from "https://deno.land/std@0.136.0/fs/mod.ts"; import { readAll } from "https://deno.land/std@0.135.0/streams/mod.ts" import { parse as argParse } from "https://deno.land/std@0.135.0/flags/mod.ts"; import { normalize, join as pathJoin, fromFileUrl, parse as parsePath , relative } from "https://deno.land/std@0.135.0/path/mod.ts"; import * as Eta from "https://deno.land/x/eta@v1.12.3/mod.ts"; import { createReactive } from "./reactivity.ts"; async function readContent(path?: string): Promise { let content = "[]"; if (path) { content = await Deno.readTextFile(path); } else if (!Deno.isatty(Deno.stdin.rid)) { const decoder = new TextDecoder(undefined, { ignoreBOM: true }); const buf = await readAll(Deno.stdin); content = decoder.decode(buf); } else throw new Error("No input provided. path or stdin."); return content; } type printDocParam = { target: string, data: { issues: Issue[] } }; async function printDoc(param: printDocParam, option?: { outDir?: string }) { option = option ?? {}; const { target, data } = param; const { outDir } = option; let print: string = ""; print = await Eta.renderFile(target, data) as string; if (outDir) { const outPath = pathJoin(outDir, target); await Deno.mkdir(pathJoin(outDir), { recursive: true }); await Deno.writeTextFile(outPath, print); } else { console.log(print); } } async function main() { const parsedArg = argParse(Deno.args); const { issue_path, outDirArg, w, watch } = parsedArg; const watchMode = w || watch; if (typeof issue_path !== "undefined" && typeof issue_path !== "string") { console.log("Please provide a path to the json file."); Deno.exit(1); } if (typeof outDirArg !== "undefined" && typeof outDirArg !== "string") { console.log("Please provide a path to the output file."); Deno.exit(1); } const outDir = (outDirArg ?? "build"); if (typeof watchMode !== "undefined" && typeof watchMode !== "boolean") { console.log("Please provide a boolean value for w."); Deno.exit(1); } if (watchMode && typeof issue_path === "undefined") { console.log("Could not set watch mode without a path."); Deno.exit(1); } const url = new URL(import.meta.url) url.pathname = normalize(pathJoin(url.pathname, "..", "template")); const viewPath = fromFileUrl(url); Eta.configure({ views: viewPath, "view cache": false, }); const issuesR = await createReactive(async () => { const c = await readContent(issue_path); const issues = JSON.parse(c) as Issue[]; issues.sort((a, b) => a.number - b.number); return issues; }); const targets = ["SUMMARY.md", "overall.md", "specific.md", "intro.md", "support.md"]; const targetsR = await Promise.all(targets.map(async (t) => { return await createReactive(async () => { await printDoc({ target: t, data: { issues: issuesR.value } }, { outDir: outDir }); }); } )); issuesR.wireTo(...targetsR); const copyOp = await createReactive(async () => { const files = [...Deno.readDirSync(viewPath)].map(x => x.name).filter(x => !x.endsWith(".md")); const op = files.map(x => copy(pathJoin(viewPath, x), pathJoin(outDir, x), { overwrite: true })); await Promise.all(op); }); if (watchMode) { const watcher = Deno.watchFs([viewPath, issue_path as string]); for await (const event of watcher) { if (event.kind === "modify") { Deno.stdout.write( new TextEncoder().encode("\x1b[2J\x1b[0f"), ); console.log(`reloading ${event.paths.join(", ")}`); for (const path of event.paths) { const p = parsePath(path); if (p.dir === viewPath) { if (p.ext === ".md") { targetsR[targets.indexOf(p.base)].update(); } else { copyOp.update(); } } else if (p.base === "issues.json") { await issuesR.update(); } } } } } } if (import.meta.main) { main(); }