Skip to content
Snippets Groups Projects
Select Git revision
  • 645c2bf39ed6decc3ca2d27f2c1a6397bd3a2dce
  • main default protected
  • renovate/django-debug-toolbar-6.x
  • renovate/jsonschema-4.x
  • renovate/django-5.x
  • koma/feature/preference-polling-form
6 results

apps.py

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    index.ts 5.84 KiB
    import fs from "node:fs/promises";
    import {
      generateIndexHtml,
      generateResolutionsHtml,
      generateTranscriptsRssXml,
      renderTranscriptPageHtml,
    } from "./lib/rendering";
    import bootstrap from "bootstrap/dist/css/bootstrap.min.css";
    import { Command } from "commander";
    import * as Path from "path";
    import { Protocol, parseProtocol, parseProtocolFromFile } from "./lib/parsing/protocol";
    
    async function main() {
      const program = new Command();
      program
        .name("fsinfo-transcript-postprocessor")
        .description("CLI to post-process markdown transcripts of FSR meetings")
        .version("unknown")
        .argument(
          "<inputDir>",
          "path to directory containing the input markdown files"
        )
        .argument("<outputDir>", "path to output the rendered html to")
        .option("-A, --output-ast", "Also save the AST as a file", false)
        .option("-B, --base-url [url]", "Basic URL for the RSS feed")
        .action(run);
      await program.parseAsync(process.argv);
    }
    main();
    
    export interface CliOptions {
      outputAst: boolean;
      baseUrl: string;
    }
    
    async function run(inputDir: string, outputDir: string, options: CliOptions) {
      // (1) Get a list of files to read
      const files = await getListOfFiles(inputDir);
    
      // (2) Parse all of them, report errors
      if (files.length > 1000) {
        throw "Too many files to be read, something is off: " + files.length;
      }
      console.info("⚙️  Parsing", files.length, "markdown files...");
    
      const protocols = await async function () {
        // parse the protocols
        const protocolsWithErrors = await Promise.all(
          files.map(file => parseProtocolFromFile(file))
        );
    
        // extract errors and exit if any exist
        const errors = protocolsWithErrors.filter(p => typeof p === "string");
        if (errors.length > 0) {
          console.error(errors.length, "transcripts had errors. Aborting.");
          process.exit(1);
        }
    
        // there are no errors, so return as Protocol[]
        return protocolsWithErrors
          .map(p => p as Protocol);
      }();
    
      // Generate transcript pages
      console.info("✏️  Writing individual HTML files...");
      await generateAllTranscriptPages(
        outputDir,
        protocols,
        options
      );
    
      // Generate index page
      console.info("✏️  Writing index file...");
      await generateIndexPage(
        outputDir,
        protocols,
        options
      );
    
      // Generate resolution list
      console.info("✏️  Writing resolutions list file...");
      await generateResolutionsPage(
        outputDir,
        protocols
      );
    
      await fs.writeFile(outputDir + "/bootstrap.min.css", bootstrap, "utf8");
    
      // Generate JSON of all data
      console.info("✏️  Writing Metadata as JSON file...");
      await fs.writeFile(
        outputDir + "/index.json",
        JSON.stringify(
          protocols.map(p => ({
            ...p.data,
            tags: null,
            categories: null,
            contents: "gone_with_this_generator_sorry",
          }))
        )
      );
    
      // Create RSS file
      console.info("✏️  Writing RSS feed index.xml...");
      const rssXml = generateTranscriptsRssXml(
        protocols,
        options.baseUrl ?? process.env.CI_PAGES_URL
      );
    
      await fs.writeFile(Path.join(outputDir, "index.xml"), rssXml);
      await fs.writeFile(Path.join(outputDir, "protokolle/index.xml"), rssXml);
    
      // Be done
      console.info("✅ All done!");
    }
    
    async function getListOfFiles(rootPath: string | undefined): Promise<string[]> {
      if (typeof rootPath !== "string") {
        throw new TypeError("Missing argument <filesDirectory>");
      }
      return (await fs.readdir(rootPath))
        .filter((path) => path.endsWith(".md"))
        .map((path) => rootPath + "/" + path)
        .reverse();
    }
    
    async function generateAllTranscriptPages(
      outputDir: string,
      protocols: Protocol[],
      options: CliOptions
    ) {
      // make sure the dir exists and is empty
      await fs.mkdir(outputDir, { recursive: true });
      await fs.rm(outputDir, {
        force: true,
        recursive: true,
      });
      await fs.mkdir(outputDir, { recursive: true });
    
      await Promise.all(
        protocols.map(p => generateTranscriptPage(p, outputDir, options)
        )
      );
    }
    
    async function generateTranscriptPage(
      protocol: Protocol,
      outputDir: string,
      options: CliOptions
    ) {
      const { data, html, ast } = protocol;
    
      if (protocol.session_type === "fsr") {
        const transcriptDir = `protokolle/fsr-sitzung-${data.number}-${data.date}`;
    
        const dir = Path.join(outputDir, transcriptDir);
        await fs.mkdir(dir, { recursive: true, });
    
        await fs.writeFile(Path.join(dir, "index.html"), html, "utf-8");
    
        const pageHtml = renderTranscriptPageHtml(protocol);
        await fs.writeFile(Path.join(dir, "index.html"), pageHtml, "utf-8");
    
        if (options.outputAst) {
          await fs.writeFile(
            Path.join(dir, "ast.json"),
            JSON.stringify(ast, null, 2),
            "utf-8"
          );
        }
      } else if (protocol.session_type === "fvv") {
        const transcriptDir = `protokolle/fvv-sitzung-${data.number}-${data.date}`;
    
        const dir = Path.join(outputDir, transcriptDir);
        await fs.mkdir(dir, { recursive: true, });
    
        const pageHtml = renderTranscriptPageHtml(protocol);
        await fs.writeFile(Path.join(dir, "index.html"), pageHtml, "utf-8");
    
        if (options.outputAst) {
          await fs.writeFile(
            Path.join(dir, "ast.json"),
            JSON.stringify(ast, null, 2),
            "utf-8"
          );
        }
      } else {
        console.log(`unknown session type ${protocol.session_type}`)
        console.log("not generating transcript page")
      }
    }
    
    async function generateIndexPage(
      outputDir: string,
      protocols: Protocol[],
      options: CliOptions
    ) {
      const html = generateIndexHtml(protocols);
    
      const htmlFilePath = outputDir + "/index.html";
      await fs.writeFile(htmlFilePath, html, "utf8");
    }
    
    async function generateResolutionsPage(
      outputDir: string,
      protocols: Protocol[]
    ) {
      const html = generateResolutionsHtml(protocols);
    
      await fs.mkdir(outputDir + "/resolutions/");
      const htmlFilePath = outputDir + "/resolutions/index.html";
      await fs.writeFile(htmlFilePath, html, "utf8");
    }