1 | 'use strict';
|
2 |
|
3 | const chalk = require('chalk');
|
4 | const charset = require('charset');
|
5 |
|
6 | const Eyo = require('eyo-kernel');
|
7 |
|
8 | const safeEyo = new Eyo();
|
9 | safeEyo.dictionary.loadSafeSync();
|
10 |
|
11 | const notSafeEyo = new Eyo();
|
12 | notSafeEyo.dictionary.loadNotSafeSync();
|
13 |
|
14 | const fs = require('fs');
|
15 | const iconv = require('iconv-lite');
|
16 | const isutf8 = require('isutf8');
|
17 | const program = require('commander');
|
18 | const request = require('request');
|
19 |
|
20 | const isWin = process.platform === 'win32';
|
21 | const okSym = isWin ? '[OK]' : '✓';
|
22 | const errSym = isWin ? '[ERR]' : '✗';
|
23 | const chalkDiff = isWin ? chalk.underline : chalk.bold;
|
24 |
|
25 | const exitCodes = {
|
26 | NOT_UTF8: 21,
|
27 | HAS_REPLACEMENT: 22,
|
28 | NO_SUCH_FILE: 23,
|
29 | UNKNOWN_CHARSET: 24
|
30 | };
|
31 |
|
32 | let isFirst = true;
|
33 |
|
34 | function printItem(color, item, i) {
|
35 | const before = item.before;
|
36 | const after = item.after;
|
37 | const newBefore = [];
|
38 | const newAfter = [];
|
39 | const info = [];
|
40 | const pos = Array.isArray(item.position) ? item.position[0] : item.position;
|
41 |
|
42 |
|
43 | for (let n = 0; n < before.length; n++) {
|
44 | if (before[n] !== after[n]) {
|
45 | newBefore[n] = chalkDiff(before[n]);
|
46 | newAfter[n] = chalkDiff(after[n]);
|
47 | } else {
|
48 | newBefore[n] = before[n];
|
49 | newAfter[n] = after[n];
|
50 | }
|
51 | }
|
52 |
|
53 | info.push(pos.line + ':' + pos.column);
|
54 |
|
55 | if (item.count > 1) {
|
56 | info.push('count: ' + item.count);
|
57 | }
|
58 |
|
59 | console.log(
|
60 | (i + 1) + '. ' +
|
61 | newBefore.join('') + ' → ' +
|
62 | newAfter.join('') +
|
63 | (info.length ? ' (' + info.join(', ') + ')' : '')
|
64 | );
|
65 | }
|
66 |
|
67 | module.exports = {
|
68 | |
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 | _processText(text, resource) {
|
75 | const n = isFirst ? '' : '\n';
|
76 |
|
77 | if (program.lint) {
|
78 | const safeReplacement = safeEyo.lint(text, program.sort);
|
79 | if (safeReplacement.length) {
|
80 | console.log(n + chalk.red(errSym) + ' ' + resource);
|
81 | } else {
|
82 | console.log(n + chalk.green(okSym) + ' ' + resource);
|
83 | }
|
84 |
|
85 | if (safeReplacement.length) {
|
86 | console.log(chalk.yellow('Safe replacements:'));
|
87 | safeReplacement.forEach(printItem.bind(this, 'red'));
|
88 |
|
89 | if (!process.exitCode) {
|
90 | process.exitCode = exitCodes.HAS_REPLACEMENT;
|
91 | }
|
92 | }
|
93 |
|
94 | if (!program.onlySafe) {
|
95 | const notSafeReplacement = notSafeEyo.lint(text, program.sort);
|
96 | if (notSafeReplacement.length) {
|
97 | console.log(chalk.red((notSafeReplacement.length ? '\n' : '') + 'Not safe replacements:'));
|
98 | notSafeReplacement.forEach(printItem.bind(this, 'yellow'));
|
99 | }
|
100 | }
|
101 | } else {
|
102 | process.stdout.write(safeEyo.restore(text));
|
103 | }
|
104 |
|
105 | isFirst = false;
|
106 | },
|
107 | |
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 | _processFile(file, callback) {
|
114 | if (fs.existsSync(file) && fs.statSync(file).isFile()) {
|
115 | const buf = fs.readFileSync(file);
|
116 | if (isutf8(buf)) {
|
117 | this._processText(buf.toString('utf8'), file);
|
118 | } else {
|
119 | console.error(chalk.red(file + ': is not UTF-8.'));
|
120 | process.exitCode = exitCodes.NOT_UTF8;
|
121 | }
|
122 | } else {
|
123 | console.error(chalk.red(file + ': no such file.'));
|
124 | process.exitCode = exitCodes.NO_SUCH_FILE;
|
125 | }
|
126 |
|
127 | callback();
|
128 | },
|
129 | |
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 | _processUrl(url, callback) {
|
136 | request.get(
|
137 | {url, gzip: true, encoding: null},
|
138 | function(error, res, buf) {
|
139 | if (error) {
|
140 | console.log(chalk.red(error));
|
141 | process.exitCode = exitCodes.ERROR_LOADING;
|
142 | }
|
143 |
|
144 | if (res && res.statusCode !== 200) {
|
145 | console.log(chalk.red(`${url}: returns status code is ${res.statusCode}.`));
|
146 | process.exitCode = exitCodes.ERROR_LOADING;
|
147 | callback();
|
148 |
|
149 | return;
|
150 | }
|
151 |
|
152 | if (isutf8(buf)) {
|
153 | this._processText(buf.toString('utf8'), url);
|
154 | } else {
|
155 | const enc = charset(res.headers['content-type'], buf);
|
156 | if (iconv.encodingExists(enc)) {
|
157 | this._processText(iconv.decode(buf, enc), url);
|
158 | } else {
|
159 | console.error(enc + ': is unknown charset.');
|
160 | process.exitCode = exitCodes.UNKNOWN_CHARSET;
|
161 | }
|
162 | }
|
163 |
|
164 | callback();
|
165 | }.bind(this));
|
166 | },
|
167 | exitCodes
|
168 | };
|