UNPKG

render-gfm

Version:

Render GitHub Flavoured Markdown, with CSS for each of GitHub's themes.

148 lines (141 loc) 11.6 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import fs from 'fs'; import path from 'path'; import prettier from 'prettier'; import { Writer } from 'steno'; import { Octokit } from 'octokit'; import getCSS from 'generate-github-markdown-css'; const octokit = new Octokit(); /** * The theme(s) to use when rendering the Markdown. */ export var Theme; (function (Theme) { Theme["Auto"] = "auto"; Theme["Light"] = "light"; Theme["Dark"] = "dark"; Theme["DarkDimmed"] = "dark_dimmed"; Theme["DarkHighContrast"] = "dark_high_contrast"; Theme["LightColorblind"] = "light_colorblind"; Theme["DarkColorblind"] = "dark_colorblind"; })(Theme || (Theme = {})); /** * A dictionary of functions that return CSS for each theme. * Auto means that if the user's system is set to dark mode, the dark theme will be used, otherwise the light theme will be used. * Light means that the light theme will be used, no matter what the user's system asks for (light mode or dark mode). * Dark, dark_dimmed, dark_high_contrast, light_colorblind, and dark_colorblind are the same thing as light (single mode, the specific theme will be used in both cases, like the user's system requesting light mode or dark mode). * * If you want a different combination (e.g. when the user's system/browser requests light mode, serve light_colorblind, but when the user's system/browser requests dark mode, serve dark), you can use the `getCSS` function from the `generate-github-markdown-css` package. * The `getCSS` function is also exported from this package for convenience. */ const themeToCSS = { auto: () => getCSS({ light: 'light', dark: 'dark' }), light: () => getCSS({ light: 'light', dark: 'light' }), dark: () => getCSS({ light: 'dark', dark: 'dark' }), dark_dimmed: () => getCSS({ light: 'dark_dimmed', dark: 'dark_dimmed' }), dark_high_contrast: () => getCSS({ light: 'dark_high_contrast', dark: 'dark_high_contrast' }), light_colorblind: () => getCSS({ light: 'light_colorblind', dark: 'light_colorblind' }), dark_colorblind: () => getCSS({ light: 'dark_colorblind', dark: 'dark_colorblind' }) }; export { getCSS }; /** * Writes a file with string data to the filesystem. * If the file does not exist, it will be created. * @param {string} file The file path to write to. Absolute or relative. * @param {string} content The string data to write to the file. */ function write(file, content) { return __awaiter(this, void 0, void 0, function* () { const fileWriter = new Writer(file); fs.mkdirSync(path.dirname(file), { recursive: true }); yield fileWriter.write(yield content); // "await content" is needed, despite VSCode's warning. String content might be a promise, and we need to wait for it to resolve. }); } /** * Generates and returns CSS for each requested theme in the `themes` array, as an object * @param {string} outputDir The directory to write the CSS files to. If unspecified, the CSS will still be returned in an object, but not written to the filesystem. * @param {Theme[]} themes An array of the themes to generate CSS for. Defaults to all themes. * @returns {Promise<Record<string, string>>} An object containing the CSS for each theme. */ export function generateCSS(outputDir, themes = [Theme.Auto, Theme.Light, Theme.Dark, Theme.DarkDimmed, Theme.DarkHighContrast, Theme.LightColorblind, Theme.DarkColorblind]) { return __awaiter(this, void 0, void 0, function* () { let stylesheets = {}; for (const theme of themes) { stylesheets[theme] = themeToCSS[theme](); } if (outputDir) { fs.mkdirSync(outputDir, { recursive: true }); for (const [name, stylesheet] of Object.entries(stylesheets)) { yield write(path.join(outputDir, `${name}.css`), stylesheet); } } return stylesheets; }); } /** * Renders Markdown to HTML. If `outputFile` is specified, the HTML will be written to the filesystem. * The resulting HTML rendered will be wrapped in a default template, unless `includeDefaultTemplate` is set to false. * This is useful for when you want to use your own HTML template. * @param {string} markdown The Markdown to render. * @param {string} outputFile The file to write the rendered HTML to. If unspecified, the HTML will still be returned, but not written to the filesystem. * @param {boolean} includeDefaultTemplate Whether or not to include the default HTML template. Default: true. If false, the rendered Markdown will not be wrapped in a template. * @returns {Promise<string>} The rendered HTML. */ export default function render(markdown, outputFile, includeDefaultTemplate = true) { return __awaiter(this, void 0, void 0, function* () { const request = yield octokit.request('POST /markdown', { text: markdown.toString(), mode: 'gfm' }); let renderedMarkdown = request.data; if (includeDefaultTemplate) { // #main adds spacing so it's not right up against the edge of the screen. The margin/padding values are GitHub's defaults when rendering Markdown using GitHub Pages. // Good max widths: '75em' or '100em' (1012px is GitHub Page's default) renderedMarkdown = `<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>GitHub Markdown</title> <link id="theme" rel="stylesheet" href="css/auto.css"> <style> #main { margin-top: 32px !important; margin-bottom: 32px !important; padding-left: 16px !important; padding-right: 16px !important; padding-top: 0 !important; padding-bottom: 0 !important; } </style> </head> <body class="markdown-body"> <article id="main" class="markdown-body" style="padding: 1em; max-width: 1012px; margin: 0px auto;"> ${request.data} </article> <select style="position: fixed; top: 1em; right: 1em; font-size: 16px; border-radius: 10px; padding: 5px;" onchange="theme.href=this.value"> <option value="css/auto.css">auto</option> <option value="css/light.css">light</option> <option value="css/dark_dimmed.css">dark dimmed</option> <option value="css/dark.css">dark</option> <option value="css/dark_high_contrast.css">dark high contrast</option> <option value="css/dark_colorblind.css">dark colorblind</option> <option value="css/light_colorblind.css">light colorblind</option> </select> </body> </html> `; } const render = yield prettier.format(renderedMarkdown, { parser: 'html', singleAttributePerLine: false, tabWidth: 4 }); if (outputFile) { yield write(outputFile, render); } return render; }); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBQUEsT0FBTyxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQ3BCLE9BQU8sSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUN4QixPQUFPLFFBQVEsTUFBTSxVQUFVLENBQUM7QUFDaEMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLE9BQU8sQ0FBQztBQUMvQixPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ2xDLE9BQU8sTUFBTSxNQUFNLDhCQUE4QixDQUFDO0FBRWxELE1BQU0sT0FBTyxHQUFHLElBQUksT0FBTyxFQUFFLENBQUM7QUFFOUI7O0dBRUc7QUFDSCxNQUFNLENBQU4sSUFBWSxLQVFYO0FBUkQsV0FBWSxLQUFLO0lBQ2Isc0JBQWEsQ0FBQTtJQUNiLHdCQUFlLENBQUE7SUFDZixzQkFBYSxDQUFBO0lBQ2IsbUNBQTBCLENBQUE7SUFDMUIsZ0RBQXVDLENBQUE7SUFDdkMsNkNBQW9DLENBQUE7SUFDcEMsMkNBQWtDLENBQUE7QUFDdEMsQ0FBQyxFQVJXLEtBQUssS0FBTCxLQUFLLFFBUWhCO0FBRUQ7Ozs7Ozs7O0VBUUU7QUFDRixNQUFNLFVBQVUsR0FBRztJQUNmLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsQ0FBQztJQUNwRCxLQUFLLEVBQUUsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUM7SUFDdEQsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxDQUFDO0lBQ25ELFdBQVcsRUFBRSxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsRUFBRSxLQUFLLEVBQUUsYUFBYSxFQUFFLElBQUksRUFBRSxhQUFhLEVBQUUsQ0FBQztJQUN4RSxrQkFBa0IsRUFBRSxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsRUFBRSxLQUFLLEVBQUUsb0JBQW9CLEVBQUUsSUFBSSxFQUFFLG9CQUFvQixFQUFFLENBQUM7SUFDN0YsZ0JBQWdCLEVBQUUsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLEVBQUUsS0FBSyxFQUFFLGtCQUFrQixFQUFFLElBQUksRUFBRSxrQkFBa0IsRUFBRSxDQUFDO0lBQ3ZGLGVBQWUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsRUFBRSxLQUFLLEVBQUUsaUJBQWlCLEVBQUUsSUFBSSxFQUFFLGlCQUFpQixFQUFFLENBQUM7Q0FDdkYsQ0FBQztBQUNGLE9BQU8sRUFBRSxNQUFNLEVBQUUsQ0FBQztBQUVsQjs7Ozs7R0FLRztBQUNILFNBQWUsS0FBSyxDQUFDLElBQVksRUFBRSxPQUFlOztRQUM5QyxNQUFNLFVBQVUsR0FBRyxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNwQyxFQUFFLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUN0RCxNQUFNLFVBQVUsQ0FBQyxLQUFLLENBQUMsTUFBTSxPQUFPLENBQUMsQ0FBQyxDQUFDLGlJQUFpSTtJQUM1SyxDQUFDO0NBQUE7QUFFRDs7Ozs7R0FLRztBQUNILE1BQU0sVUFBZ0IsV0FBVyxDQUFDLFNBQWlCLEVBQUUsU0FBa0IsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsVUFBVSxFQUFFLEtBQUssQ0FBQyxnQkFBZ0IsRUFBRSxLQUFLLENBQUMsZUFBZSxFQUFFLEtBQUssQ0FBQyxjQUFjLENBQUM7O1FBQy9MLElBQUksV0FBVyxHQUEyQixFQUFFLENBQUM7UUFDN0MsS0FBSyxNQUFNLEtBQUssSUFBSSxNQUFNLEVBQUUsQ0FBQztZQUN6QixXQUFXLENBQUMsS0FBSyxDQUFDLEdBQUcsVUFBVSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDN0MsQ0FBQztRQUNELElBQUksU0FBUyxFQUFFLENBQUM7WUFDWixFQUFFLENBQUMsU0FBUyxDQUFDLFNBQVMsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1lBQzdDLEtBQUssTUFBTSxDQUFDLElBQUksRUFBRSxVQUFVLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUM7Z0JBQzNELE1BQU0sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLEdBQUcsSUFBSSxNQUFNLENBQUMsRUFBRSxVQUFVLENBQUMsQ0FBQztZQUNqRSxDQUFDO1FBQ0wsQ0FBQztRQUNELE9BQU8sV0FBVyxDQUFDO0lBQ3ZCLENBQUM7Q0FBQTtBQUVEOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxDQUFDLE9BQU8sVUFBZ0IsTUFBTSxDQUFDLFFBQWdCLEVBQUUsVUFBa0IsRUFBRSx5QkFBa0MsSUFBSTs7UUFDN0csTUFBTSxPQUFPLEdBQUcsTUFBTSxPQUFPLENBQUMsT0FBTyxDQUFDLGdCQUFnQixFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsQ0FBQyxRQUFRLEVBQUUsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUVwRyxJQUFJLGdCQUFnQixHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUM7UUFDcEMsSUFBSSxzQkFBc0IsRUFBRSxDQUFDO1lBQ3pCLHNLQUFzSztZQUN0Syx1RUFBdUU7WUFDdkUsZ0JBQWdCLEdBQUc7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Y0F5QmIsT0FBTyxDQUFDLElBQUk7Ozs7Ozs7Ozs7Ozs7OztDQWV6QixDQUFDO1FBQ0UsQ0FBQztRQUVELE1BQU0sTUFBTSxHQUFHLE1BQU0sUUFBUSxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsRUFBRSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsc0JBQXNCLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBRXZILElBQUksVUFBVSxFQUFFLENBQUM7WUFDYixNQUFNLEtBQUssQ0FBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDcEMsQ0FBQztRQUVELE9BQU8sTUFBTSxDQUFDO0lBQ2xCLENBQUM7Q0FBQSJ9