@reason.co/docugen
Version:
`npm i docugen` (private npm install for now)
129 lines (108 loc) • 3.69 kB
JavaScript
const fs = require('fs-extra');
const path = require('path');
const os = require('os');
const mdToPdf = require('md-to-pdf');
const marked = require('marked');
const yaml = require('js-yaml');
const singleHeadingRegex = /^(#+)\s+(.*)$/;
const allHeadingsRegex = new RegExp(singleHeadingRegex, 'gm');
const renderToc = (headings, maxDepth = 3) => {
const markdown = headings
.slice(1) // ignore h1
.map((heading) => {
try {
const [hashes, title] = heading.match(singleHeadingRegex);
const headingLevel = hashes.length - 1;
if (headingLevel <= maxDepth) {
return `${' '.repeat(headingLevel - 1)}1. ${title}`;
}
} catch(e){
console.log('Bad heading',heading,e);
}
})
.filter(Boolean)
.join('\n');
return `<div class="toc">${marked(markdown)}</div>`;
};
async function renderFile(
srcFile,
outDir,
tmpDir,
version,
projectname,
helperHtml,
config
) {
let markdownSource = includeFile(srcFile);
const filename = path.basename(srcFile);
const headings = [];
/*
const markdownWithHeadings = markdownSource.replace(
allHeadingsRegex,
(headingLine) => {
headings.push(headingLine);
return headingLine;
}
);
*/
const markdownCombined = [helperHtml, markdownSource]
.join('\r\n\r\n')
.replace(/\[\[\s*TOC\s*]]/i, renderToc(headings))
.replace(/{fileName}/g, filename)
.replace(/{projectname}/g, projectname)
.replace(/{runDate}/g, new Date().toLocaleString())
.replace(/{version}/g, version);
await fs.writeFile(`${tmpDir}/${filename}`, markdownCombined);
const dest = `${outDir}/${path.basename(filename, '.md')}.pdf`;
const mergedPdf = await mdToPdf(`${tmpDir}/${filename}`, { ...config, dest });
return mergedPdf.filename.replace(process.cwd(), '');
}
function includeFile(srcFile) {
return fs
.readFileSync(srcFile, 'utf8')
.replace(/\[\[\s*include\s+(['"])(.+)\1\s*]]/g, (_1, _2, relativePath) =>
includeFile(path.resolve(path.dirname(srcFile), relativePath))
);
}
async function renderFolder(args) {
let {sourcedir, destdir, version, projectname} = args.opts;
//const pkg = require('../../../package.json');
//const [majorVersion, minorVersion] = pkg.version.split('.');
const filenames = fs.readdirSync(sourcedir).filter((elm) => elm.match(/\.md$/i));
const tmpDir = fs.mkdtempSync(`${os.tmpdir()}/docgen`);
await fs.copy(sourcedir, tmpDir);
await fs.copy(`${__dirname}/fonts`, `${tmpDir}/fonts`);
await fs.ensureDir(destdir);
const [configYaml, helperHtml, pageHeader, pageFooter] = [
'config.yml',
'helpers.html',
'header.html',
'footer.html',
].map((file) => fs.readFileSync(`${__dirname}/templates/${file}`, 'utf8'));
const pageFooterWithVersion = pageFooter
.replace(/{versionNumber}/g, version)
.replace(/{projectname}/g, projectname)
.replace(/{runDate}/g, new Date().toLocaleString());
const config = yaml.safeLoad(configYaml);
// stylesheet paths are relative to CWD by default so make them absolute
config.stylesheet = config.stylesheet.map((file) => `${__dirname}/${file}`);
config.pdf_options.headerTemplate = pageHeader;
config.pdf_options.footerTemplate = pageFooterWithVersion;
const generatedFiles = await Promise.all(
filenames.map((filename) =>
renderFile(
`${sourcedir}/${filename}`,
destdir,
tmpDir,
version,
projectname,
helperHtml,
config,
)
)
);
console.info('Created PDF docs:');
console.info(generatedFiles.map((name) => `- ${name}`).join('\n'));
}
module.exports = renderFolder;