UNPKG

marshmallow

Version:

README Parser – easy as marshmallow!

161 lines (147 loc) 7.84 kB
const { exec } = require('child_process') const { existsSync } = require('fs') const { outputFile } = require('fs-extra') const { minify } = require('html-minifier') const { Markdown } = require('markdown-to-html') const { basename, dirname, extname, resolve } = require('path') const { open } = require('psd') const { error, warn } = console const markdown = new Markdown() module.exports = (options = {}) => { const config = getConfig(options) if (!config.force && existsSync(config.output)) { warn('[warn] File output exist!') process.exit(2) } parse(config) } function generate (data, config) { const html = ` <html lang="en"> <head> <meta charset="utf-8"> <meta name="msapplication-TileColor" content="${config.color}" /> <meta name="msapplication-TileImage" content="${config.image}" /> <meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-status-bar-style" content="${config.color}" /> <meta name="apple-mobile-web-app-title" content="${config.title}" /> <meta name="application-name" content="${config.title}" /> <meta name="format-detection" content="telephone=no" /> <meta name="theme-color" content="${config.color}" /> <meta name="robots" content="index,follow" /> <meta name="author" content="${config.author}" /> <meta name="description" content="${config.description}" /> <meta property="og:description" content="${config.description}" /> <meta property="og:image" content="${config.image}" /> <meta property="og:locale" content="en" /> <meta property="og:site_name" content="${config.title}" /> <meta property="og:title" content="${config.title}" /> <meta property="og:type" content="website" /> <meta property="og:url" content="${config.url}" /> <meta property="article:published_time" content="${new Date().toISOString()}"> <meta property="article:author" content="${config.author}" /> <meta property="article:section" content="website" /> <meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:domain" content="${config.title}" /> <meta name="twitter:url" content="${config.url}" /> <meta name="twitter:site" content="${config.url}" /> <meta name="twitter:creator" content="${config.author}" /> <meta name="twitter:title" content="${config.title}" /> <meta name="twitter:description" content="${config.description}" /> <meta name="twitter:image:src" content="${config.image}" /> <title>${config.title}</title> <base href="${config.url}"> <link rel="canonical" href="${config.url}"> <link rel="apple-touch-icon" href="${config.image}" /> <link rel="shortcut icon" href="${config.image}" /> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.0/milligram.min.css"> <style>h2{font-size:2.8rem;line-height:1.3;}h2:nth-child(n+1){margin-top:15.0rem;}.container{max-width:80.0rem;}</style> <style>:root{--main-color:${ config.color };}.button,button,input[type='button'],input[type='reset'],input[type='submit']{background-color:var(--main-color);border-color:var(--main-color);}.button[disabled]:focus,.button[disabled]:hover,button[disabled]:focus,button[disabled]:hover,input[type='button'][disabled]:focus,input[type='button'][disabled]:hover,input[type='reset'][disabled]:focus,input[type='reset'][disabled]:hover,input[type='submit'][disabled]:focus,input[type='submit'][disabled]:hover{background-color:var(--main-color);border-color:var(--main-color)}.button.button-outline,button.button-outline,input[type='button'].button-outline,input[type='reset'].button-outline,input[type='submit'].button-outline{color:var(--main-color);}.button.button-outline[disabled]:focus,.button.button-outline[disabled]:hover,button.button-outline[disabled]:focus,button.button-outline[disabled]:hover,input[type='button'].button-outline[disabled]:focus,input[type='button'].button-outline[disabled]:hover,input[type='reset'].button-outline[disabled]:focus,input[type='reset'].button-outline[disabled]:hover,input[type='submit'].button-outline[disabled]:focus,input[type='submit'].button-outline[disabled]:hover{color:var(--main-color)}.button.button-clear,button.button-clear,input[type='button'].button-clear,input[type='reset'].button-clear,input[type='submit'].button-clear{color:var(--main-color)}.button.button-clear[disabled]:focus,.button.button-clear[disabled]:hover,button.button-clear[disabled]:focus,button.button-clear[disabled]:hover,input[type='button'].button-clear[disabled]:focus,input[type='button'].button-clear[disabled]:hover,input[type='reset'].button-clear[disabled]:focus,input[type='reset'].button-clear[disabled]:hover,input[type='submit'].button-clear[disabled]:focus,input[type='submit'].button-clear[disabled]:hover{color:var(--main-color)}pre{background:#f4f5f6;border-left:0.3rem solid var(--main-color);}input[type='email']:focus,input[type='number']:focus,input[type='password']:focus,input[type='search']:focus,input[type='tel']:focus,input[type='text']:focus,input[type='url']:focus,textarea:focus,select:focus{border-color:var(--main-color);}select:focus{background-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="14" viewBox="0 0 29 14" width="29"><path fill="var(--main-color)" d="M9.37727 3.625l5.08154 6.93523L19.54036 3.625"/></svg>')}a{color:var(--main-color);}</style> </head> <body> <div class="container"> ${data} </div> </body> </html> ` .trim() .replace(/&lt;/g, '<') .replace(/&gt;/g, '>') .replace(/&quot;/g, '"') .replace(/<\/a><br><a /g, '</a> <a ') .replace(/.psd/g, '.png') .replace(/<h2 id="license">License<\/h2>/g, '<h2 id="license"></h2>') outputFile(config.output, minify(html, config.minify), err => { err ? error('[error] Error!') : copyImage(config.image, config.output) }) } function copyImage (input, output) { if (input.indexOf('cjpatoilo.com') !== -1) { process.exit(1) } if (!existsSync(input)) { error('[error] Image no exist!') process.exit(2) } if (extname(input) === '.psd') { open(input).then(psd => psd.image.saveAsPng(`${dirname(output)}/${basename(input, '.psd')}.png`), ) } else { exec(`cp ${resolve(__dirname, input)} ${dirname(output)}`) } } function parse (config) { markdown.bufmax = 100000 markdown.render(config.readme, {}, err => err ? error(err) : markdown.on('data', data => generate(data, config)), ) } function output (value) { return extname(value).length ? resolve(dirname(value), 'index.html') : resolve(value, 'index.html') } function readmeCheck (value) { if (!existsSync(value)) { error(`[error] ${value} no exist!`) process.exit(2) } return value } function colorCheck (value = '') { return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test( value[0] === '#' ? value : '#' + value, ) } function getConfig (options = {}) { const minify = { collapseBooleanAttributes: true, removeComments: true, collapseWhitespace: true, } return { output: output(options.output || options.o || 'index.html'), readme: readmeCheck(options.readme || options.r || 'readme.md'), minify: options.minify || options.m ? minify : {}, author: options.author || options.a || options.title || options.t || 'Unknown', image: options.image || options.i || 'https://cjpatoilo.com/marshmallow/artwork.png', title: options.title || options.t || 'Marshmallow', description: options.description || options.d || 'README Parser – easy as marshmallow!', color: colorCheck(options.color || options.c) || '#d1d1d1', url: options.url || options.u || '/', force: options.force || options.f, } }