UNPKG

5.52 kBJavaScriptView Raw
1'use strict';
2
3const fs = require('fs');
4const pth = require('path');
5const escape = require('escape-html');
6
7const {
8 hasEngRusLetters,
9 replaceEngLettersWithAsterisk,
10 replaceRusLettersWithAsterisk,
11} = require('../helpers/string');
12const { getTyposByCode, hasManyErrors } = require('../helpers/typos');
13const { isUrl } = require('../helpers/url');
14const { uptime } = require('../helpers/uptime');
15const { consoleError, consoleInfo } = require('../helpers/console');
16
17const yaspeller = require('../yaspeller');
18
19const buffer = [];
20
21function makeLink(resource) {
22 let href = resource;
23 let relativeFile = resource;
24
25 if (!isUrl(resource)) {
26 relativeFile = pth.relative('.', resource);
27 // CI: short links
28 if (relativeFile.indexOf('..') !== -1) {
29 relativeFile = resource;
30 }
31
32 href = fileUrl(href);
33 }
34
35 return '<a target="_blank" href="' +
36 escape(encodeURI(href)) + '" title="' +
37 escape(resource) + '">' +
38 escape(relativeFile) + '</a>';
39}
40
41function fileUrl(file) {
42 return 'file://localhost' +
43 (file.search(/^\//) === -1 ? '/' : '') +
44 file.replace(/\\/g, '/');
45}
46
47function prepareTemplate(params) {
48 return `<!DOCTYPE html>
49<html>
50 <head>
51 <meta charset="utf-8"/>
52 <title>yaspeller report</title>
53 <style>${params.css}</style>
54 </head>
55 <body class="show-only-errors_checked">
56 <div class="page">${params.content}</div>
57 <script>${params.js}</script>
58 </body>
59</html>`;
60}
61
62function loadFile(filename) {
63 return fs.readFileSync(pth.join(__dirname, 'html/' + filename)).toString();
64}
65
66const filename = 'yaspeller_report.html';
67
68module.exports = {
69 name: 'html',
70 onResourceComplete(err, data) {
71 const html = [];
72 if (err) {
73 html.push('<div class="syserr">' + data + '</div>');
74 } else {
75 const time = data.time ? '<span class="time">' + data.time + ' ms</span>' : '';
76 if (data.data && data.data.length) {
77 html.push('<div class="err"><span class="sym-err">χ</span>' + makeLink(data.resource) + time + '</div>');
78 } else {
79 html.push('<div class="ok"><span class="sym-ok">✓</span>' + makeLink(data.resource) + time + '</div>');
80 }
81
82 html.push('<div class="typo">');
83 if (hasManyErrors(data.data)) {
84 html.push('<div class="title">Too many errors.</div>');
85 }
86
87 yaspeller.errors.forEach(function(el) {
88 const typos = getTyposByCode(el.code, data.data);
89 if (typos.length) {
90 html.push('<table class="table"><caption>' + el.title + '</caption>');
91 html.push('<tr><th class="table-num">Num.</th>' +
92 '<th class="table-name">Typo</th>' +
93 '<th class="table-line">Line:Col</th>' +
94 '<th class="table-suggest">Suggest</th>' +
95 '<th class="table-comment">Comment</th></tr>');
96 typos.forEach(function(el, i) {
97 const comment = [];
98 const pos = el.position;
99 const suggest = el.suggest ? el.suggest.map(w => '<span class="word">' + escape(w) + '</span>').join(', ') : '';
100
101 if (hasEngRusLetters(el.word)) {
102 comment.push('<code class="letters-en">en: ' + escape(replaceRusLettersWithAsterisk(el.word)) + '</code>');
103 comment.push('<code class="letters-ru">ru: ' + escape(replaceEngLettersWithAsterisk(el.word)) + '</code>');
104 }
105
106 html.push('<tr>');
107 html.push('<td class="table-num">' + (i + 1) + '.</td>');
108 html.push('<td class="table-name"><span class="word">' + escape(el.word) + '</span>' +
109 (el.count > 1 ? '<sup class="table-count">' + el.count + '</sup>' : '') +
110 '</td>');
111 html.push('<td class="table-line">' + (pos.length ? pos[0].line + ':' + pos[0].column : '') + '</td>');
112 html.push('<td class="table-suggest">' + suggest + '</td>');
113 html.push('<td class="table-comment">' + (comment.length ? comment.join('<br/>') : '') + '</td>');
114 html.push('</tr>');
115 });
116
117 html.push('</table>');
118 }
119 });
120
121 html.push('</div>');
122 }
123
124 buffer.push(html.join('\n'));
125 },
126 onComplete(data, stats) {
127 const content = '<div class="total">Processed resources: ' + stats.total +
128 ' (<span class="sym-err">χ</span>– ' + stats.errors +
129 '</span>, <span class="sym-ok-group"><span class="sym-ok">✓</span>– ' + stats.ok + '</span>) ' +
130 '<label><input class="show-only-errors" autocomplete="off" checked="checked" type="checkbox" /> Only errors</label>' +
131 '<br/>Checking finished: ' + uptime() + '</div>' +
132 buffer.join('');
133
134 try {
135 fs.writeFileSync(filename, prepareTemplate({
136 css: loadFile('template.css'),
137 js: loadFile('template.js'),
138 content: content
139 }));
140 consoleInfo('HTML report: ./' + filename);
141 } catch (e) {
142 consoleError(e);
143 }
144 },
145};