OurBigBook logoOurBigBook Docs OurBigBook logoOurBigBook.comSite Source code
marked/docs/build.js
/* global marked */
import '../lib/marked.umd.js';
import { promises } from 'fs';
import { join, dirname, parse, format } from 'path';
import { fileURLToPath } from 'url';
import { markedHighlight } from 'marked-highlight';
import { HighlightJS } from 'highlight.js';
import titleize from 'titleize';
import { getTests } from '@markedjs/testutils';

const { mkdir, rm, readdir, stat, readFile, writeFile, copyFile } = promises;
const { highlight, highlightAuto } = HighlightJS;
const cwd = process.cwd();
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const inputDir = join(cwd, 'docs');
const outputDir = join(cwd, 'public');
const templateFile = join(inputDir, '_document.html');
const isUppercase = str => /[A-Z_]+/.test(str);
const getTitle = str => str === 'INDEX' ? '' : titleize(str.replace(/_/g, ' ')) + ' - ';
function convertTestsToTable(name, tests) {
  let total = 0;
  let passing = 0;
  let table = '\n| Section | Passing | Percent |\n';
  table += '|:--------|:--------|--------:|\n';
  for (const [key, value] of Object.entries(tests)) {
    total += value.total;
    passing += value.pass;
    table += ` | ${key}`;
    table += ` | ${(value.pass)} of ${(value.total)}`;
    table += ` | ${((value.pass) / value.total * 100).toFixed()}%`;
    table += ' |\n';
  }
  return `\n<details name="markdown-spec">
  <summary>${name} (${(passing / total * 100).toFixed()}%)</summary>
  ${table}
</details>\n`;
}

const markedInstance = new marked.Marked(markedHighlight((code, language) => {
  if (!language) {
    return highlightAuto(code).value;
  }
  return highlight(code, { language }).value;
}));

async function init() {
  console.log('Cleaning up output directory ' + outputDir);
  await rm(outputDir, { force: true, recursive: true });
  await mkdir(outputDir);
  await mkdir(join(outputDir, 'lib'));
  console.log(`Copying file ${join(inputDir, 'LICENSE.md')}`);
  await copyFile(join(cwd, 'LICENSE'), join(inputDir, 'LICENSE.md'));
  console.log(`Copying file ${join(outputDir, 'lib/marked.umd.js')}`);
  await copyFile(join(cwd, 'lib/marked.umd.js'), join(outputDir, 'lib/marked.umd.js'));
  console.log(`Copying file ${join(outputDir, 'lib/marked.umd.js.map')}`);
  await copyFile(join(cwd, 'lib/marked.umd.js.map'), join(outputDir, 'lib/marked.umd.js.map'));
  console.log(`Copying file ${join(outputDir, 'lib/marked.esm.js')}`);
  await copyFile(join(cwd, 'lib/marked.esm.js'), join(outputDir, 'lib/marked.esm.js'));
  console.log(`Copying file ${join(outputDir, 'lib/marked.esm.js.map')}`);
  await copyFile(join(cwd, 'lib/marked.esm.js.map'), join(outputDir, 'lib/marked.esm.js.map'));
  const tmpl = await readFile(templateFile, 'utf8');
  console.log('Building markdown...');
  const [original, commonmark, gfm] = await getTests([
    join(__dirname, '../test/specs/original'),
    join(__dirname, '../test/specs/commonmark'),
    join(__dirname, '../test/specs/gfm'),
  ]);
  const testResultsTable =
    convertTestsToTable('Markdown 1.0', original)
    + convertTestsToTable('CommonMark 0.31', commonmark)
    + convertTestsToTable('GitHub Flavored Markdown 0.29', gfm);
  await build(inputDir, tmpl, testResultsTable);
  console.log('Build complete!');
}

const ignoredFiles = [
  join(cwd, 'docs', 'build.js'),
  join(cwd, 'docs', '.eslintrc.json'),
  join(cwd, 'docs', '_document.html'),
];

async function build(currentDir, tmpl, testResultsTable) {
  const files = await readdir(currentDir);
  for (const file of files) {
    const filename = join(currentDir, file);
    if (ignoredFiles.includes(filename)) {
      continue;
    }
    const stats = await stat(filename);
    const { mode } = stats;
    if (stats.isDirectory()) {
      await build(filename, tmpl);
    } else {
      let html = await readFile(filename, 'utf8');
      const parsed = parse(filename);
      if (parsed.ext === '.md' && isUppercase(parsed.name)) {
        const mdHtml = markedInstance.parse(
          html.replace('<!--{{test-results-table}}-->', testResultsTable),
        );
        html = tmpl
          .replace('<!--{{title}}-->', getTitle(parsed.name))
          .replace('<!--{{content}}-->', mdHtml);
        parsed.ext = '.html';
        parsed.name = parsed.name.toLowerCase();
        delete parsed.base;
      }
      parsed.dir = parsed.dir.replace(inputDir, outputDir);
      const outfile = format(parsed);
      await mkdir(dirname(outfile), { recursive: true });
      console.log('Writing file ' + outfile);
      await writeFile(outfile, html, { mode });
    }
  }
}

init().catch(console.error);