UNPKG

phtml

Version:

A tool for transforming HTML with JavaScript

183 lines (162 loc) 4.96 kB
#!/usr/bin/env node 'use strict'; function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var child_process = require('child_process'); var fs = _interopDefault(require('fs')); var path = _interopDefault(require('path')); var PHTML = _interopDefault(require('.')); const argo = getArgo(); const configPath = argo.config === true ? 'phtml.config.js' : argo.config ? String(argo.config) : false; (argo.from === '<stdin>' ? getStdin() : readFile(argo.from)).then(html => { try { const config = configPath ? safeRequire(configPath) : {}; const plugins = [].concat(config.plugins || []).concat(argo.plugins && typeof argo.plugins === 'string' ? argo.plugins.split(',') : []); config.plugins = plugins.map(plugin => { const normalizedPlugin = Array.isArray(plugin) ? plugin.length > 1 ? safeRequire(plugin[0])(plugin[1]) : safeRequire(plugin[0]) : typeof plugin === 'string' ? safeRequire(plugin) : plugin; return normalizedPlugin; }); return { config, html }; } catch (error) { console.log('Something went wrong!'); console.log(Object(error).message || error); } return { config: {}, html }; }).then(({ config, html }) => { if (argo.from === '<stdin>' && !html) { logInstructions(); process.exit(0); } const processOptions = { from: argo.from, to: argo.to || argo.from }; if (typeof argo.map === 'string') { processOptions.map = JSON.parse(argo.map); } Object.assign(processOptions, config.options); const plugins = [].concat(config.plugins || []); return PHTML.use(plugins).process(html, processOptions).then(result => { if (argo.to === '<stdout>') { return result.html; } else { return writeFile(argo.to, result.html).then(() => `HTML has been written to "${argo.to}"`); } }); }).catch(error => { if (Object(error).errno === -2) { throw new Error(`Sorry, "${error.path}" could not be read.`); } throw error; }).then(result => { console.log(result); process.exit(0); }, error => { console.error(Object(error).message || 'Something bad happened and we don’t even know what it was.'); process.exit(1); }); function getArgo() { return process.argv.slice(2).reduce((object, arg, i, args) => { // eslint-disable-line max-params const dash = /^--([^\s]+)$/; if (dash.test(getArgName(arg))) { object[getArgName(arg).replace(dash, '$1')] = i + 1 in args ? args[i + 1] : true; } else if (!dash.test(getArgName(args[i - 1]))) { if (object.from === '<stdin>') { object.from = arg; } else if (object.to === '<stdout>') { object.to = arg; } } return object; }, { from: '<stdin>', to: '<stdout>', plugins: '' }); function getArgName(arg) { return { '-c': '--config', '-i': '--from', '-o': '--to', '-p': '--plugins' }[arg] || arg; } } function getStdin() { return new Promise(resolve => { let data = ''; if (process.stdin.isTTY) { resolve(data); } else { process.stdin.setEncoding('utf8'); process.stdin.on('readable', () => { let chunk; while (chunk = process.stdin.read()) { data += chunk; } }); process.stdin.on('end', () => { resolve(data); }); } }); } function readFile(pathname) { return new Promise((resolve, reject) => { fs.readFile(pathname, 'utf8', (error, data) => { if (error) { reject(error); } else { resolve(data); } }); }); } function writeFile(pathname, data) { return new Promise((resolve, reject) => { fs.writeFile(pathname, data, (error, content) => { if (error) { reject(error); } else { resolve(content); } }); }); } function logInstructions() { console.log(['pHTML\n', ' Transform HTML with JavaScript\n', 'Usage:\n', ' phtml source.html ouput.html', ' phtml --from source.html --to ouput.html', ' phtml --from source.html --to ouput.html --plugins @phtml/markdown', ' phtml -i source.html -o ouput.html -p @phtml/markdown', ' echo "<title>html</title>" | phtml -p @phtml/markdown'].join('\n') + '\n'); } function safeRequire(id) { try { // 1st, attempt to require the id as a package or filepath return require(id); } catch (error) { try { // 2nd, attempt to require the id as a resolved filepath return require(path.resolve(id)); } catch (error2) { try { // 3rd, attempt to install and require the id as a package pipeExec(`npm install --no-save ${id}`); return require(id); } catch (error3) { // otherwise, throw the original error throw error; } } } } function pipeExec(cmd, opts) { return child_process.execSync(cmd, Object.assign({ stdio: ['pipe', 'pipe', process.stderr] }, opts)); }