UNPKG

4.96 kBJavaScriptView Raw
1#!/usr/bin/env node
2'use strict';
3
4function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
5
6var child_process = require('child_process');
7var fs = _interopDefault(require('fs'));
8var path = _interopDefault(require('path'));
9var PHTML = _interopDefault(require('.'));
10
11const argo = getArgo();
12const configPath = argo.config === true ? 'phtml.config.js' : argo.config ? String(argo.config) : false;
13(argo.from === '<stdin>' ? getStdin() : readFile(argo.from)).then(html => {
14 try {
15 const config = configPath ? safeRequire(configPath) : {};
16 const plugins = [].concat(config.plugins || []).concat(argo.plugins && typeof argo.plugins === 'string' ? argo.plugins.split(',') : []);
17 config.plugins = plugins.map(plugin => {
18 const normalizedPlugin = Array.isArray(plugin) ? plugin.length > 1 ? safeRequire(plugin[0])(plugin[1]) : safeRequire(plugin[0]) : typeof plugin === 'string' ? safeRequire(plugin) : plugin;
19 return normalizedPlugin;
20 });
21 return {
22 config,
23 html
24 };
25 } catch (error) {
26 console.log('Something went wrong!');
27 console.log(Object(error).message || error);
28 }
29
30 return {
31 config: {},
32 html
33 };
34}).then(({
35 config,
36 html
37}) => {
38 if (argo.from === '<stdin>' && !html) {
39 logInstructions();
40 process.exit(0);
41 }
42
43 const processOptions = {
44 from: argo.from,
45 to: argo.to || argo.from
46 };
47
48 if (typeof argo.map === 'string') {
49 processOptions.map = JSON.parse(argo.map);
50 }
51
52 Object.assign(processOptions, config.options);
53 const plugins = [].concat(config.plugins || []);
54 return PHTML.use(plugins).process(html, processOptions).then(result => {
55 if (argo.to === '<stdout>') {
56 return result.html;
57 } else {
58 return writeFile(argo.to, result.html).then(() => `HTML has been written to "${argo.to}"`);
59 }
60 });
61}).catch(error => {
62 if (Object(error).errno === -2) {
63 throw new Error(`Sorry, "${error.path}" could not be read.`);
64 }
65
66 throw error;
67}).then(result => {
68 console.log(result);
69 process.exit(0);
70}, error => {
71 console.error(Object(error).message || 'Something bad happened and we don’t even know what it was.');
72 process.exit(1);
73});
74
75function getArgo() {
76 return process.argv.slice(2).reduce((object, arg, i, args) => {
77 // eslint-disable-line max-params
78 const dash = /^--([^\s]+)$/;
79
80 if (dash.test(getArgName(arg))) {
81 object[getArgName(arg).replace(dash, '$1')] = i + 1 in args ? args[i + 1] : true;
82 } else if (!dash.test(getArgName(args[i - 1]))) {
83 if (object.from === '<stdin>') {
84 object.from = arg;
85 } else if (object.to === '<stdout>') {
86 object.to = arg;
87 }
88 }
89
90 return object;
91 }, {
92 from: '<stdin>',
93 to: '<stdout>',
94 plugins: ''
95 });
96
97 function getArgName(arg) {
98 return {
99 '-c': '--config',
100 '-i': '--from',
101 '-o': '--to',
102 '-p': '--plugins'
103 }[arg] || arg;
104 }
105}
106
107function getStdin() {
108 return new Promise(resolve => {
109 let data = '';
110
111 if (process.stdin.isTTY) {
112 resolve(data);
113 } else {
114 process.stdin.setEncoding('utf8');
115 process.stdin.on('readable', () => {
116 let chunk;
117
118 while (chunk = process.stdin.read()) {
119 data += chunk;
120 }
121 });
122 process.stdin.on('end', () => {
123 resolve(data);
124 });
125 }
126 });
127}
128
129function readFile(pathname) {
130 return new Promise((resolve, reject) => {
131 fs.readFile(pathname, 'utf8', (error, data) => {
132 if (error) {
133 reject(error);
134 } else {
135 resolve(data);
136 }
137 });
138 });
139}
140
141function writeFile(pathname, data) {
142 return new Promise((resolve, reject) => {
143 fs.writeFile(pathname, data, (error, content) => {
144 if (error) {
145 reject(error);
146 } else {
147 resolve(content);
148 }
149 });
150 });
151}
152
153function logInstructions() {
154 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');
155}
156
157function safeRequire(id) {
158 try {
159 // 1st, attempt to require the id as a package or filepath
160 return require(id);
161 } catch (error) {
162 try {
163 // 2nd, attempt to require the id as a resolved filepath
164 return require(path.resolve(id));
165 } catch (error2) {
166 try {
167 // 3rd, attempt to install and require the id as a package
168 pipeExec(`npm install --no-save ${id}`);
169 return require(id);
170 } catch (error3) {
171 // otherwise, throw the original error
172 throw error;
173 }
174 }
175 }
176}
177
178function pipeExec(cmd, opts) {
179 return child_process.execSync(cmd, Object.assign({
180 stdio: ['pipe', 'pipe', process.stderr]
181 }, opts));
182}