to_pdf.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #!/usr/bin/env node
  2. const fs = require("fs");
  3. const path = require("path");
  4. const yaml = require("yaml");
  5. const { exec, execSync } = require("child_process");
  6. const puppeteer = require("puppeteer");
  7. const pug = require("pug");
  8. function parseData(dataFilePath) {
  9. return yaml.parse(fs.readFileSync(dataFilePath, { encoding: "utf8" }));
  10. }
  11. function createHtml(pugFile, data, outputPath) {
  12. const rendered = pug.renderFile(pugFile, data);
  13. fs.writeFile(outputPath, rendered, (err) => {
  14. if (err) throw err;
  15. });
  16. }
  17. async function printPDF(url) {
  18. const browser = await puppeteer.launch({ headless: "new" });
  19. const page = await browser.newPage();
  20. await page.goto(url, { waitUntil: "networkidle0" });
  21. const pdf = await page.pdf({ format: "A4" });
  22. await browser.close();
  23. return pdf;
  24. }
  25. function exportToPdf(htmlFile, pdfPath) {
  26. url = `file://${path.resolve(htmlFile)}`;
  27. printPDF(url).then((pdf) => {
  28. fs.writeFile(pdfPath, pdf, (err) => {
  29. if (err) throw err;
  30. });
  31. });
  32. }
  33. function exportRenderToPdf(dataFilePath, templatePath, assetsPath, outputPath, outputBasename) {
  34. const data = parseData(dataFilePath);
  35. const revPath = path.join(outputPath, `${outputBasename}.revision.txt`);
  36. const htmlPath = path.join(outputPath, `${outputBasename}.html`);
  37. const pdfPath = path.join(outputPath, `${outputBasename}.pdf`);
  38. const newAssetsPath = path.join(outputPath, "assets");
  39. fs.mkdirSync(outputPath, { recursive: true });
  40. fs.mkdirSync(newAssetsPath, { recursive: true });
  41. fs.cpSync(assetsPath, newAssetsPath, { recursive: true });
  42. createHtml(templatePath, data, htmlPath);
  43. console.log(`Wrote HTML file to ${htmlPath}`);
  44. exportToPdf(htmlPath, pdfPath);
  45. console.log(`Wrote PDF file to ${pdfPath}`);
  46. writeGitRevisionFile(dataFilePath, templatePath, assetsPath, revPath);
  47. }
  48. function writeGitRevisionFile(dataFilePath, templatePath, assetsPath, revPath) {
  49. const allFiles = `${dataFilePath} ${templatePath} ${assetsPath}`;
  50. const dirty = areDirty(allFiles);
  51. const cmd = `git log --format="%H" ${allFiles} | head -1`;
  52. exec(cmd, (err, stdout, stderr) => {
  53. if (err) {
  54. return;
  55. }
  56. const newRev = dirty ? `#${stdout}` : stdout;
  57. fs.appendFile(revPath, newRev, (err) => {
  58. if (err) throw err;
  59. });
  60. console.log(`Wrote ${dirty ? "dirty" : "clean"} revision data to ${revPath}`);
  61. });
  62. }
  63. function areDirty(fileList) {
  64. const dirtyStatusCmd = `git diff --quiet ${fileList}`;
  65. try {
  66. execSync(dirtyStatusCmd);
  67. return false;
  68. } catch {
  69. return true;
  70. }
  71. }
  72. const [inputPath, variantName, outputPath] = process.argv.slice(2);
  73. if (!inputPath || !variantName || !outputPath) {
  74. console.error(`The script should be called like :\n${process.argv[1]} input_path variant_name output_dir`);
  75. process.exit(1);
  76. }
  77. const inputDirName = inputPath.split(path.sep).at(-1);
  78. const dataFilePath = path.join(inputPath, `${variantName}.yaml`);
  79. const templatePath = path.join(inputPath, `template.pug`);
  80. const assetsPath = path.join(inputPath, "assets");
  81. exportRenderToPdf(dataFilePath, templatePath, assetsPath, outputPath, `${inputDirName}_${variantName}`);