fuzzyworld

auto-print / files / src / cli.ts

cli.ts

2.6 KB · history · blame

1#!/usr/bin/env node
2// auto-print: turns markdown manuscripts into epub, docx, pdf and Kindle kpf files.
3//
4// auto-print build every book in ./books.json
5// auto-print wick-canyon build only the named book(s)
6// auto-print --config path/books.json
7// auto-print --list list the configured books
8
9import { buildBook } from "./build.ts";
10import { loadConfig } from "./config.ts";
11import { displayPath, fail } from "./util.ts";
12
13const usage = `Usage: auto-print [--config <file>] [--list] [slug ...]
14
15 --config <file> The config file. Default: books.json in the current folder.
16 --list List the books in the config file, and build nothing.
17 slug ... Build only these books. Without a slug, every book is built.`;
18
19export async function main(args: string[]): Promise<number> {
20 let configPath = "books.json";
21 let list = false;
22 const slugs: string[] = [];
23 for (let index = 0; index < args.length; index++) {
24 const arg = args[index]!;
25 if (arg === "--help" || arg === "-h") {
26 console.log(usage);
27 return 0;
28 } else if (arg === "--list") {
29 list = true;
30 } else if (arg === "--config") {
31 configPath = args[++index] ?? fail("--config needs a file name.");
32 } else if (arg.startsWith("-")) {
33 fail(`Unknown option: ${arg}\n\n${usage}`);
34 } else {
35 slugs.push(arg);
36 }
37 }
38
39 const config = loadConfig(configPath);
40 if (list) {
41 for (const book of config.books) console.log(`${book.slug}\t${book.title}\t${displayPath(book.source)}`);
42 return 0;
43 }
44
45 const unknown = slugs.filter((slug) => !config.books.some((book) => book.slug === slug));
46 if (unknown.length > 0) {
47 fail(`Unknown book: ${unknown.join(", ")}. Known books: ${config.books.map((b) => b.slug).join(", ")}.`);
48 }
49 const selected = slugs.length > 0 ? config.books.filter((book) => slugs.includes(book.slug)) : config.books;
50
51 let failures = 0;
52 for (const book of selected) {
53 console.log(`\n${book.title} (${displayPath(book.source)})`);
54 try {
55 if ((await buildBook(book, config.outDir)) > 0) failures += 1;
56 } catch (error) {
57 failures += 1;
58 console.error(` FAILED: ${(error as Error).message}`);
59 }
60 }
61 if (failures > 0) {
62 console.error(`\n${failures} of ${selected.length} book(s) had failures.`);
63 return 1;
64 }
65 console.log(`\nDone. ${selected.length} book(s) built into ${config.outDir}`);
66 return 0;
67}
68
69main(process.argv.slice(2)).then(
70 (code) => { process.exitCode = code; },
71 (error) => {
72 console.error(`Error: ${(error as Error).message}`);
73 process.exitCode = 1;
74 },
75);