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/command.ts | 200 ------------------------------------------- nuldoc-src/commands/build.ts | 170 ++++++++++++++++++++++++++++++++++++ nuldoc-src/commands/serve.ts | 22 +++++ nuldoc-src/main.ts | 12 ++- 4 files changed, 202 insertions(+), 202 deletions(-) delete mode 100644 nuldoc-src/command.ts create mode 100644 nuldoc-src/commands/build.ts create mode 100644 nuldoc-src/commands/serve.ts (limited to 'nuldoc-src') diff --git a/nuldoc-src/command.ts b/nuldoc-src/command.ts deleted file mode 100644 index 57e4820..0000000 --- a/nuldoc-src/command.ts +++ /dev/null @@ -1,200 +0,0 @@ -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 { serveDir } from "std/http/file_server.ts"; -import { serve } from "std/http/server.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 run(command: string, config: Config) { - if (command === "build") { - await cmdBuild(config); - } else if (command === "serve") { - cmdServe(config); - } else { - console.error(`Unknown command: ${command}`); - } -} - -async function cmdBuild(config: Config) { - const posts = await generatePosts(config); - await generateTags(posts, config); - await generatePostList(posts, config); - await generateAboutPage(config); - await copyStaticFiles(config); -} - -function cmdServe(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, - }); - }); -} - -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/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, + }); + }); +} diff --git a/nuldoc-src/main.ts b/nuldoc-src/main.ts index c7c175b..1635d76 100644 --- a/nuldoc-src/main.ts +++ b/nuldoc-src/main.ts @@ -1,6 +1,14 @@ +import { runBuildCommand } from "./commands/build.ts"; +import { runServeCommand } from "./commands/serve.ts"; import { config } from "./config.ts"; -import { run } from "./command.ts"; if (import.meta.main) { - await run(Deno.args[0] ?? "build", config); + const command = Deno.args[0] ?? "build"; + if (command === "build") { + await runBuildCommand(config); + } else if (command === "serve") { + runServeCommand(config); + } else { + console.error(`Unknown command: ${command}`); + } } -- cgit v1.2.3-70-g09d2