Skip to content

Instantly share code, notes, and snippets.

@erwinv
Created March 26, 2021 04:22
Show Gist options
  • Save erwinv/8e85847fdfe8889c9cbd181a8e364980 to your computer and use it in GitHub Desktop.
Save erwinv/8e85847fdfe8889c9cbd181a8e364980 to your computer and use it in GitHub Desktop.
Generate API document from Markdown
import { promises as fs } from 'fs';
import { JSDOM } from 'jsdom';
import MarkdownIt from 'markdown-it';
import open from 'open';
import { tmpdir } from 'os';
import { join as joinPath } from 'path';
import request from 'request-promise-native';
import SVGO from 'svgo';
const PLANTUML_SERVER = 'https://www.plantuml.com/plantuml'
const md = MarkdownIt({
html: true,
linkify: true,
typographer: true,
})
.use(require('markdown-it-plantuml'), {
server: PLANTUML_SERVER,
openMarker: '```plantuml',
closeMarker: '```',
imageFormat: 'svg',
})
.use(require('markdown-it-highlightjs'))
.use(require('markdown-it-anchor'), {
permalink: true,
permalinkBefore: true,
permalinkSymbol: '§',
})
.use(require('markdown-it-toc-done-right'))
.use(require('markdown-it-multimd-table'), {
rowspan: true,
});
const svgBg = `svg {
background-color: white;
}`;
const runningAsmain = require.main === module;
if (runningAsmain) {
const [, , inputFile, outputFile, ...cssFiles] = process.argv;
const outputHtmlFile = outputFile ?? joinPath(tmpdir(), 'api_doc.html');
Promise.all([
fs.readFile(inputFile, 'utf8').then((mdStr) => md.render(mdStr)),
...cssFiles.map(cssFile => fs.readFile(cssFile, 'utf8')),
])
.then(([mdBody, ...csss]) => `<html><head><style>${csss.join('\n')}</style></head><body class="markdown-body">${mdBody}</body></html>`)
.then(replaceImgsWithInlineSvgs)
.then((mdHtml) => fs.writeFile(outputHtmlFile, mdHtml))
.then(() => open(outputHtmlFile))
.catch(() => process.exit(1));
}
async function replaceImgsWithInlineSvgs(htmlBody: string) {
const dom = new JSDOM(htmlBody);
const images = Array.from(dom.window.document.querySelectorAll('img'));
const svgo = new SVGO();
await Promise.all(images
.filter(({ src }) => src.startsWith(`${PLANTUML_SERVER}/svg/`))
.map(async (image) => {
const resp = await request(image.src);
const inlineSvg = dom.window.document.createElement('div');
inlineSvg.innerHTML = await svgo.optimize(resp).then(({ data }) => data);
const oldImage = image.parentNode?.replaceChild(inlineSvg, image);
}))
.catch((err) => {
console.log(`Please make sure that PlantUML service is running and listening at ${PLANTUML_SERVER}.`);
throw err;
});
return dom.serialize();
}
{
"name": "bin",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"github-markdown-css": "^4.0.0",
"highlight.js": "^10.1.1",
"jsdom": "^16.3.0",
"markdown-it-anchor": "^5.3.0",
"markdown-it": "^11.0.0",
"markdown-it-highlightjs": "^3.2.0",
"markdown-it-multimd-table": "^4.0.3",
"markdown-it-plantuml": "^1.4.1",
"markdown-it-toc-done-right": "^4.1.0",
"markdown-retro": "^0.0.1",
"open": "^7.0.4",
"request-promise-native": "^1.0.8",
"svgo": "^1.3.2"
},
"devDependencies": {
"@types/jsdom": "^16.2.3",
"@types/markdown-it": "^10.0.2",
"@types/request-promise-native": "^1.0.17",
"@types/svgo": "^1.3.3"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment