1 | #!/usr/bin/env node
|
2 | 'use strict';
|
3 |
|
4 | function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
5 |
|
6 | var child_process = require('child_process');
|
7 | var fs = _interopDefault(require('fs'));
|
8 | var path = _interopDefault(require('path'));
|
9 | var PHTML = _interopDefault(require('.'));
|
10 |
|
11 | const argo = getArgo();
|
12 | const 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 |
|
75 | function getArgo() {
|
76 | return process.argv.slice(2).reduce((object, arg, i, args) => {
|
77 |
|
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 |
|
107 | function 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 |
|
129 | function 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 |
|
141 | function 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 |
|
153 | function 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 |
|
157 | function safeRequire(id) {
|
158 | try {
|
159 |
|
160 | return require(id);
|
161 | } catch (error) {
|
162 | try {
|
163 |
|
164 | return require(path.resolve(id));
|
165 | } catch (error2) {
|
166 | try {
|
167 |
|
168 | pipeExec(`npm install --no-save ${id}`);
|
169 | return require(id);
|
170 | } catch (error3) {
|
171 |
|
172 | throw error;
|
173 | }
|
174 | }
|
175 | }
|
176 | }
|
177 |
|
178 | function pipeExec(cmd, opts) {
|
179 | return child_process.execSync(cmd, Object.assign({
|
180 | stdio: ['pipe', 'pipe', process.stderr]
|
181 | }, opts));
|
182 | }
|