1 | var assert = require('assert');
|
2 | var chalk = require('chalk');
|
3 | var TokenAssert = require('./token-assert');
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | var Errors = function(file, verbose) {
|
13 | this._errorList = [];
|
14 | this._file = file;
|
15 | this._currentRule = '';
|
16 | this._verbose = verbose || false;
|
17 |
|
18 | |
19 |
|
20 |
|
21 |
|
22 | this.assert = new TokenAssert(file);
|
23 | this.assert.on('error', this._addError.bind(this));
|
24 | };
|
25 |
|
26 | Errors.prototype = {
|
27 | |
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 | add: function(message, line, column) {
|
35 | if (typeof line === 'object') {
|
36 | column = line.column;
|
37 | line = line.line;
|
38 | }
|
39 |
|
40 | var errorInfo = {
|
41 | message: message,
|
42 | line: line,
|
43 | column: column
|
44 | };
|
45 |
|
46 | this._validateInput(errorInfo);
|
47 | this._addError(errorInfo);
|
48 | },
|
49 |
|
50 | |
51 |
|
52 |
|
53 |
|
54 |
|
55 | cast: function(errorInfo) {
|
56 | var additional = errorInfo.additional;
|
57 |
|
58 | assert(typeof additional !== undefined,
|
59 | '`additional` argument should not be empty');
|
60 |
|
61 | this._addError(errorInfo);
|
62 | },
|
63 |
|
64 | _validateInput: function(errorInfo) {
|
65 | var line = errorInfo.line;
|
66 | var column = errorInfo.column;
|
67 |
|
68 |
|
69 | assert(typeof line === 'number' && line > 0,
|
70 | 'Unable to add an error, `line` should be a number greater than 0 but ' +
|
71 | line + ' given');
|
72 |
|
73 | assert(typeof column === 'number' && column >= 0,
|
74 | 'Unable to add an error, `column` should be a positive number but ' +
|
75 | column + ' given');
|
76 | },
|
77 |
|
78 | |
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 | _addError: function(errorInfo) {
|
85 | if (!this._file.isEnabledRule(this._currentRule, errorInfo.line)) {
|
86 | return;
|
87 | }
|
88 |
|
89 | this._validateInput(errorInfo);
|
90 |
|
91 | this._errorList.push({
|
92 | filename: this._file.getFilename(),
|
93 | rule: this._currentRule,
|
94 | message: this._prepareMessage(errorInfo),
|
95 | line: errorInfo.line,
|
96 | column: errorInfo.column,
|
97 | additional: errorInfo.additional,
|
98 | fixed: errorInfo.fixed
|
99 | });
|
100 | },
|
101 |
|
102 | |
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 | _prepareMessage: function(errorInfo) {
|
109 | if (this._verbose && this._currentRule) {
|
110 | return this._currentRule + ': ' + errorInfo.message;
|
111 | }
|
112 |
|
113 | return errorInfo.message;
|
114 | },
|
115 |
|
116 | |
117 |
|
118 |
|
119 |
|
120 |
|
121 | getErrorList: function() {
|
122 | return this._errorList;
|
123 | },
|
124 |
|
125 | |
126 |
|
127 |
|
128 |
|
129 |
|
130 | getFilename: function() {
|
131 | return this._file.getFilename();
|
132 | },
|
133 |
|
134 | |
135 |
|
136 |
|
137 |
|
138 |
|
139 | isEmpty: function() {
|
140 | return this._errorList.length === 0;
|
141 | },
|
142 |
|
143 | |
144 |
|
145 |
|
146 |
|
147 |
|
148 | getErrorCount: function() {
|
149 | return this._errorList.length;
|
150 | },
|
151 |
|
152 | |
153 |
|
154 |
|
155 |
|
156 |
|
157 | stripErrorList: function(length) {
|
158 | this._errorList.splice(length);
|
159 | },
|
160 |
|
161 | |
162 |
|
163 |
|
164 |
|
165 |
|
166 | filter: function(filter) {
|
167 | this._errorList = this._errorList.filter(filter);
|
168 | },
|
169 |
|
170 | |
171 |
|
172 |
|
173 |
|
174 |
|
175 |
|
176 |
|
177 | explainError: function(error, colorize) {
|
178 | var lineNumber = error.line - 1;
|
179 | var lines = this._file.getLines();
|
180 | var result = [
|
181 | renderLine(lineNumber, lines[lineNumber], colorize),
|
182 | renderPointer(error.column, colorize)
|
183 | ];
|
184 | var i = lineNumber - 1;
|
185 | var linesAround = 2;
|
186 | while (i >= 0 && i >= (lineNumber - linesAround)) {
|
187 | result.unshift(renderLine(i, lines[i], colorize));
|
188 | i--;
|
189 | }
|
190 | i = lineNumber + 1;
|
191 | while (i < lines.length && i <= (lineNumber + linesAround)) {
|
192 | result.push(renderLine(i, lines[i], colorize));
|
193 | i++;
|
194 | }
|
195 | result.unshift(formatErrorMessage(error.message, this.getFilename(), colorize));
|
196 | return result.join('\n');
|
197 | },
|
198 |
|
199 | |
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 | setCurrentRule: function(rule) {
|
206 | this._currentRule = rule;
|
207 | }
|
208 |
|
209 | };
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 | function formatErrorMessage(message, filename, colorize) {
|
220 | return (colorize ? chalk.bold(message) : message) +
|
221 | ' at ' +
|
222 | (colorize ? chalk.green(filename) : filename) + ' :';
|
223 | }
|
224 |
|
225 |
|
226 |
|
227 |
|
228 |
|
229 |
|
230 |
|
231 |
|
232 | function prependSpaces(s, len) {
|
233 | while (s.length < len) {
|
234 | s = ' ' + s;
|
235 | }
|
236 | return s;
|
237 | }
|
238 |
|
239 |
|
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 |
|
246 |
|
247 | function renderLine(n, line, colorize) {
|
248 |
|
249 |
|
250 | line = line.replace(/\t/g, ' ');
|
251 |
|
252 |
|
253 | var lineNumber = prependSpaces((n + 1).toString(), 5) + ' |';
|
254 | return ' ' + (colorize ? chalk.grey(lineNumber) : lineNumber) + line;
|
255 | }
|
256 |
|
257 |
|
258 |
|
259 |
|
260 |
|
261 |
|
262 |
|
263 |
|
264 |
|
265 | function renderPointer(column, colorize) {
|
266 | var res = (new Array(column + 9)).join('-') + '^';
|
267 | return colorize ? chalk.grey(res) : res;
|
268 | }
|
269 |
|
270 | module.exports = Errors;
|