From 29bcdc6c1bad2240d404de9dca2463e46fdc1e93 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Fri, 17 Mar 2023 02:10:54 +0900 Subject: refactor: split command.ts --- nuldoc-src/commands/build.ts | 170 +++++++++++++++++++++++++++++++++++++++++++ nuldoc-src/commands/serve.ts | 22 ++++++ 2 files changed, 192 insertions(+) create mode 100644 nuldoc-src/commands/build.ts create mode 100644 nuldoc-src/commands/serve.ts (limited to 'nuldoc-src/commands') diff --git a/nuldoc-src/commands/build.ts b/nuldoc-src/commands/build.ts new file mode 100644 index 0000000..734f520 --- /dev/null +++ b/nuldoc-src/commands/build.ts @@ -0,0 +1,170 @@ +import { dirname, join, joinGlobs } from "std/path/mod.ts"; +import { ensureDir } from "std/fs/mod.ts"; +import { expandGlob } from "std/fs/expand_glob.ts"; +import { Config } from "../config.ts"; +import { parseDocBookFile } from "../docbook/parse.ts"; +import { writeHtmlFile } from "../html.ts"; +import { Document } from "../docbook/document.ts"; +import convertPost from "../templates/post.ts"; +import convertPostList from "../templates/post_list.ts"; +import convertTag from "../templates/tag.ts"; +import generateAbout from "../templates/about.ts"; + +export async function runBuildCommand(config: Config) { + const posts = await generatePosts(config); + await generateTags(posts, config); + await generatePostList(posts, config); + await generateAboutPage(config); + await copyStaticFiles(config); +} + +async function generatePosts(config: Config) { + const sourceDir = join(Deno.cwd(), config.locations.contentDir, "posts"); + const postFiles = await collectPostFiles(sourceDir); + const posts = await parsePosts(postFiles, config); + await outputPosts(posts, config); + return posts; +} + +async function collectPostFiles(sourceDir: string): Promise { + const filePaths = []; + const globPattern = joinGlobs([sourceDir, "**", "*.xml"]); + for await (const entry of expandGlob(globPattern)) { + filePaths.push(entry.path); + } + return filePaths; +} + +async function parsePosts( + postFiles: string[], + config: Config, +): Promise { + const posts = []; + for (const postFile of postFiles) { + posts.push( + await convertPost(await parseDocBookFile(postFile, config), config), + ); + } + return posts; +} + +async function outputPosts(posts: Document[], config: Config) { + const cwd = Deno.cwd(); + const contentDir = join(cwd, config.locations.contentDir); + const destDir = join(cwd, config.locations.destDir); + for (const post of posts) { + const destFilePath = join( + post.sourceFilePath.replace(contentDir, destDir).replace(".xml", ""), + "index.html", + ); + await ensureDir(dirname(destFilePath)); + await writeHtmlFile(post, destFilePath); + } +} + +async function generatePostList(posts: Document[], config: Config) { + const postList = await buildPostListDoc(posts, config); + await outputPostList(postList, config); +} + +async function buildPostListDoc( + posts: Document[], + config: Config, +): Promise { + return await convertPostList(posts, config); +} + +async function outputPostList(postList: Document, config: Config) { + const cwd = Deno.cwd(); + const destDir = join(cwd, config.locations.destDir); + const destFilePath = join(destDir, "posts", "index.html"); + await ensureDir(dirname(destFilePath)); + await writeHtmlFile(postList, destFilePath); +} + +async function generateAboutPage(config: Config) { + const aboutDoc = await generateAbout(config); + await outputAboutPage(aboutDoc, config); +} + +async function outputAboutPage(about: Document, config: Config) { + const cwd = Deno.cwd(); + const destDir = join(cwd, config.locations.destDir); + const destFilePath = join(destDir, "about", "index.html"); + await ensureDir(dirname(destFilePath)); + await writeHtmlFile(about, destFilePath); +} + +async function generateTags(posts: Document[], config: Config) { + const tagsAndPosts = collectTags(posts); + const tagDocs = await buildTagDocs(tagsAndPosts, config); + await outputTags(tagDocs, config); +} + +function collectTags(posts: Document[]): [string, Document[]][] { + const tagsAndPosts = new Map(); + for (const post of posts) { + for (const tag of post.tags) { + if (!tagsAndPosts.has(tag)) { + tagsAndPosts.set(tag, []); + } + tagsAndPosts.get(tag).push(post); + } + } + + const result: [string, Document[]][] = []; + for (const tag of Array.from(tagsAndPosts.keys()).sort()) { + result.push([ + tag, + tagsAndPosts.get(tag).sort((a: Document, b: Document) => { + const ta = a.revisions[0].date; + const tb = b.revisions[0].date; + if (ta > tb) return -1; + if (ta < tb) return 1; + return 0; + }), + ]); + } + return result; +} + +async function buildTagDocs( + tagsAndPosts: [string, Document[]][], + config: Config, +): Promise<[string, Document][]> { + const docs: [string, Document][] = []; + for (const [tag, posts] of tagsAndPosts) { + docs.push([tag, await buildTagDoc(tag, posts, config)]); + } + return docs; +} + +async function buildTagDoc( + tag: string, + posts: Document[], + config: Config, +): Promise { + return await convertTag(tag, posts, config); +} + +async function outputTags(tagDocs: [string, Document][], config: Config) { + const cwd = Deno.cwd(); + const destDir = join(cwd, config.locations.destDir); + for (const [tag, tagDoc] of tagDocs) { + const destFilePath = join(destDir, "tags", tag, "index.html"); + await ensureDir(dirname(destFilePath)); + await writeHtmlFile(tagDoc, destFilePath); + } +} + +async function copyStaticFiles(config: Config) { + const globPattern = joinGlobs([Deno.cwd(), config.locations.staticDir, "*"]); + for await (const entry of expandGlob(globPattern)) { + const src = entry.path; + const dst = src.replace( + config.locations.staticDir, + config.locations.destDir, + ); + await Deno.copyFile(src, dst); + } +} diff --git a/nuldoc-src/commands/serve.ts b/nuldoc-src/commands/serve.ts new file mode 100644 index 0000000..b66ad2d --- /dev/null +++ b/nuldoc-src/commands/serve.ts @@ -0,0 +1,22 @@ +import { join } from "std/path/mod.ts"; +import { serveDir } from "std/http/file_server.ts"; +import { serve } from "std/http/server.ts"; +import { Config } from "../config.ts"; + +export function runServeCommand(config: Config) { + const rootDir = join(Deno.cwd(), config.locations.destDir); + serve(async (req) => { + const pathname = new URL(req.url).pathname; + if (!pathname.endsWith("css") && !pathname.endsWith("svg")) { + const p = Deno.run({ + cmd: ["./nuldoc", "build"], + }); + await p.status(); + console.log("rebuild"); + } + return serveDir(req, { + fsRoot: rootDir, + showIndex: true, + }); + }); +} -- cgit v1.2.3-70-g09d2