to_pdf.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  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 cleanString(string) {
  34. return string.replaceAll(" ", "_");
  35. }
  36. function exportRenderToPdf(dataFilePath, templatePath, assetsPath, outputPath) {
  37. const data = parseData(dataFilePath);
  38. const outputBasename = `CV_${cleanString(data.basics.name)}_${cleanString(data.basics.label)}`;
  39. const revPath = path.join(outputPath, `${outputBasename}.revision.txt`);
  40. const htmlPath = path.join(outputPath, `${outputBasename}.html`);
  41. const pdfPath = path.join(outputPath, `${outputBasename}.pdf`);
  42. const newAssetsPath = path.join(outputPath, "assets");
  43. fs.mkdirSync(outputPath, { recursive: true });
  44. fs.mkdirSync(newAssetsPath, { recursive: true });
  45. fs.cpSync(assetsPath, newAssetsPath, { recursive: true });
  46. createHtml(templatePath, data, htmlPath);
  47. console.log(`Wrote HTML file to ${htmlPath}`);
  48. exportToPdf(htmlPath, pdfPath);
  49. console.log(`Wrote PDF file to ${pdfPath}`);
  50. writeGitRevisionFile(dataFilePath, templatePath, assetsPath, revPath);
  51. }
  52. function writeGitRevisionFile(dataFilePath, templatePath, assetsPath, revPath) {
  53. const allFiles = `${dataFilePath} ${templatePath} ${assetsPath}`;
  54. const dirty = areDirty(allFiles);
  55. const cmd = `git log --format="%H" ${allFiles} | head -1`;
  56. exec(cmd, (err, stdout, stderr) => {
  57. if (err) {
  58. return;
  59. }
  60. const newRev = dirty ? `#${stdout}` : stdout;
  61. fs.appendFile(revPath, newRev, (err) => {
  62. if (err) throw err;
  63. });
  64. console.log(`Wrote ${dirty ? "dirty" : "clean"} revision data to ${revPath}`);
  65. });
  66. }
  67. function areDirty(fileList) {
  68. const dirtyStatusCmd = `git diff --quiet ${fileList}`;
  69. try {
  70. execSync(dirtyStatusCmd);
  71. return false;
  72. } catch {
  73. return true;
  74. }
  75. }
  76. const [inputPath, variantName, outputPath] = process.argv.slice(2);
  77. if (!inputPath || !variantName || !outputPath) {
  78. console.error(`The script should be called like :\n${process.argv[1]} input_path variant_name output_dir`);
  79. process.exit(1);
  80. }
  81. const dataFilePath = path.join(inputPath, `${variantName}.yaml`);
  82. const templatePath = path.join(inputPath, `template.pug`);
  83. const assetsPath = path.join(inputPath, "assets");
  84. exportRenderToPdf(dataFilePath, templatePath, assetsPath, outputPath);