#!/usr/bin/env node import { readFileSync, existsSync } from "fs"; import path from "path"; import fs from "vinyl-fs"; import yargs from "yargs"; import * as CSS from "./css.js"; import { streamHTML, toHTML } from "./html.js"; const cli = yargs(process.argv.slice(2)) .config("config", function (path) { return JSON.parse(readFileSync(path), "utf-8"); }) .scriptName("gmi-web") .command("$0 [files..]", "Convert text/gemini to text/html.", (yargs) => yargs .example("$0 --body < ~/my-capsule/index.gmi") .example("$0 --html en $(find ~/my-capsule -name '*.gmi')") .example( "$0 --foreground '#000000' --background '#EEEEEE' --html en < doc.gmi" ) .example("$0 --image jpg --audio mp3 --image png --body < doc.gmi") .epilog("See the gmi-web(1) man page for more information.") ) .options({ body: { type: "boolean", group: "Core:", }, html: { type: "string", requiresArg: true, group: "Core:", }, css: { requiresArg: true, group: "Core:", }, dir: { type: "string", hidden: true, choices: ["rtl", "ltr"], default: "ltr", requiresArg: true, group: "HTML:", }, author: { type: "string", requiresArg: true, group: "HTML:", }, descriptions: { coerce: (arg) => (typeof arg === "number" ? arg : arg ? Infinity : 0), group: "HTML:", }, charset: { type: "string", hidden: true, default: "utf-8", requiresArg: true, group: "HTML:", }, image: { type: "array", requiresArg: true, group: "Media:", }, audio: { type: "array", requiresArg: true, group: "Media:", }, video: { type: "array", requiresArg: true, group: "Media:", }, inline: { type: "boolean", hidden: true, group: "CSS:", }, }); const css = yargs(process.argv.slice(2)).exitProcess(false).argv.css || "gmi-web.css"; const CSS_VARS = CSS.rootVariables(CSS.load({ css })); Object.keys(CSS_VARS).forEach((key) => { const opt = key.replace("--", ""); cli.option(opt, { default: CSS_VARS[key] }); cli.conflicts(opt, "core"); cli.conflicts(opt, "none"); }); cli.group( Object.keys(CSS_VARS).map((key) => key.replace("--", "")), `${css}:` ); const argv = cli .conflicts("author", "body") .conflicts("html", "body") .alias("html", "language") .alias("html", "lang") .showHelpOnFail(true) .help().argv; if (!argv.html && !argv.body) { cli.showHelp(); console.error(`\nMissing required argument: --html or --body`); cli.exit(1); } argv.inlineCSS = CSS.inline(argv); argv.styleTag = CSS.style(argv); if (!argv.files) { let gemtext; try { gemtext = readFileSync(process.stdin.fd, "utf-8"); } catch (e) { cli.showHelp(); console.error("\nMissing files: pipe from stdin or provide [files..]"); cli.exit(1); } console.log(toHTML(gemtext, argv)); } else { fs.src(argv.files) .pipe(streamHTML(argv)) .pipe(fs.dest((file) => path.dirname(file.path))); }