#! /usr/bin/env -S deno run --allow-read // Generate README.md from data/ and README.md.in. import markdownTOC from "npm:markdown-toc"; const dataDir = "data"; const readmeTemplateFile = "README.md.in"; type Item = { demo: string; github: string; name: string; note: string; screenshots: string[]; website: string; }; if (Deno.args.length !== 0) { console.error("usage: generate-readme.ts"); Deno.exit(1); } const readData = async (...args: string[]): Promise => { try { const text = await Deno.readTextFile([dataDir, ...args].join("/")); return text.replace(/\n+$/, ""); } catch (e) { if (e instanceof Deno.errors.NotFound) { return ""; } throw e; } }; const renderItem = ( { demo, github, name, note, screenshots, website }: Item, ): string => { const screenshotMarkdown = screenshots.map((filename) => `[![${filename}](thumbnail/${filename})](screenshot/${filename})` ).join("\n"); return `### ${name}\n\n` + (note === "" ? "" : `${note}\n\n`) + (website === "" ? "" : `* [Website](${website})\n`) + (github === "" ? "" : `* [Repository](https://github.com/${github}) ![GitHub stars](https://img.shields.io/github/stars/${github}?style=flat-square) ` + `![GitHub contributors](https://img.shields.io/github/contributors-anon/${github}?style=flat-square) ` + `![Last commit](https://img.shields.io/github/last-commit/${github}?style=flat-square) ` + `![GitHub open issues](https://img.shields.io/github/issues-raw/${github}?style=flat-square) ` + `![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/${github}?style=flat-square)\n`) + (demo === "" ? "" : `* [Demo](${demo})\n\n`) + screenshotMarkdown; }; try { const sections: { [key: string]: string } = {}; for await (const entry of Deno.readDir(dataDir)) { if (!entry.isDirectory) continue; const sectionDir = entry.name; const items: Item[] = []; for await (const entry of Deno.readDir(`${dataDir}/${sectionDir}`)) { if (!entry.isDirectory) continue; const itemDir = entry.name; const data: Item = { demo: await readData(sectionDir, itemDir, "demo"), github: await readData(sectionDir, itemDir, "github"), name: await readData(sectionDir, itemDir, "name"), note: await readData(sectionDir, itemDir, "note"), screenshots: (await readData(sectionDir, itemDir, "screenshots")).split( "\n", ), website: await readData(sectionDir, itemDir, "website"), }; items.push(data); } items.sort((a, b) => a["name"].toLowerCase().localeCompare(b["name"].toLowerCase()) ); sections[sectionDir] = items.map(renderItem).join("\n\n\n"); } const template = (await Deno.readTextFile(readmeTemplateFile)).replace( /\n+$/, "", ); let readme = template; for (const [name, markup] of Object.entries(sections)) { readme = readme.replace(`%${name.toUpperCase()}%`, markup); } readme = readme.replace("%TOC%", markdownTOC(readme).content); console.log(readme); } catch (err) { console.error(err); }