1 | checkstyleUtil = { |
---|
2 | errors: [], |
---|
3 | |
---|
4 | commentNames: ["summary", "description", "example", "tags", "this"] |
---|
5 | }; |
---|
6 | |
---|
7 | checkstyleUtil.applyRules = function(fileName, contents){ |
---|
8 | // Do not process JSON files |
---|
9 | if(contents.charAt(0) == "{"){ |
---|
10 | return; |
---|
11 | } |
---|
12 | |
---|
13 | // Mark all the characters that are in comments. |
---|
14 | var comments = checkstyleUtil.getComments(contents); |
---|
15 | |
---|
16 | // Apply all the rules to the file |
---|
17 | for(var ruleName in checkstyleUtil.rules){ |
---|
18 | checkstyleUtil.rules[ruleName](fileName, contents, comments); |
---|
19 | } |
---|
20 | }; |
---|
21 | |
---|
22 | // Calculate the characters in a file that are in comment fields |
---|
23 | // These will be ignored by the checkstyle rules. |
---|
24 | checkstyleUtil.getComments = function(contents){ |
---|
25 | var comments = []; |
---|
26 | |
---|
27 | var i; |
---|
28 | |
---|
29 | // Initialize the array to false values. |
---|
30 | for(i = 0; i < contents.length; i++){ |
---|
31 | comments[i] = 0; |
---|
32 | } |
---|
33 | |
---|
34 | var sep = "\n"; |
---|
35 | |
---|
36 | function markRange(start, stop){ |
---|
37 | for(var i = start; i < stop; i++){ |
---|
38 | comments[i] = 1; |
---|
39 | } |
---|
40 | } |
---|
41 | |
---|
42 | |
---|
43 | function markRegexs() { |
---|
44 | var idx = contents.indexOf("/g"); |
---|
45 | var i; |
---|
46 | while(idx > -1) { |
---|
47 | if(!comments[idx] && contents.charAt(idx - 1) != "*"){ |
---|
48 | // Look back until either a forward slash |
---|
49 | // or a new line is found |
---|
50 | var prevChar = contents.charAt(idx - 1); |
---|
51 | i = idx; |
---|
52 | while(prevChar != "\n" && prevChar != "/" && i > 0){ |
---|
53 | prevChar = contents.charAt(--i); |
---|
54 | } |
---|
55 | if(prevChar == "/" && i < idx - 1){ |
---|
56 | markRange(i, idx); |
---|
57 | } |
---|
58 | } |
---|
59 | idx = contents.indexOf("/g", idx + 2) |
---|
60 | } |
---|
61 | |
---|
62 | // Now mark all .match and .replace function calls |
---|
63 | // They generally contain regular expressions, and are just too bloody difficult. |
---|
64 | var fnNames = ["match", "replace"]; |
---|
65 | var name; |
---|
66 | |
---|
67 | for (i = 0; i < fnNames.length; i++){ |
---|
68 | name = fnNames[i]; |
---|
69 | |
---|
70 | idx = contents.indexOf(name + "("); |
---|
71 | |
---|
72 | while(idx > -1){ |
---|
73 | // Find the end parenthesis |
---|
74 | if(comments[idx]){ |
---|
75 | idx = contents.indexOf(name + "(", idx + name.length); |
---|
76 | } else { |
---|
77 | var fnEnd = contents.indexOf(")", idx); |
---|
78 | markRange(idx, fnEnd + 1); |
---|
79 | } |
---|
80 | } |
---|
81 | } |
---|
82 | |
---|
83 | // Now look for all the lines that declare a regex variable, e.g. |
---|
84 | // var begRegExp = /^,|^NOT |^AND |^OR |^\(|^\)|^!|^&&|^\|\|/i; |
---|
85 | |
---|
86 | idx = contents.indexOf(" = /"); |
---|
87 | |
---|
88 | while(idx > -1){ |
---|
89 | if(!comments[idx] && contents.charAt(idx + 4) != "*"){ |
---|
90 | var eol = contents.indexOf("\n", idx + 1); |
---|
91 | markRange(idx + 3, Math.max(eol, idx + 4)); |
---|
92 | } |
---|
93 | |
---|
94 | idx = contents.indexOf(" = /", idx + 3); |
---|
95 | } |
---|
96 | } |
---|
97 | |
---|
98 | markRegexs(); |
---|
99 | |
---|
100 | |
---|
101 | var marker = null; |
---|
102 | var ch; |
---|
103 | |
---|
104 | var DOUBLE_QUOTE = 1; |
---|
105 | var SINGLE_QUOTE = 2; |
---|
106 | var LINE_COMMENT = 3; |
---|
107 | var MULTI_COMMENT = 4; |
---|
108 | var UNMARK = 5; |
---|
109 | |
---|
110 | var pos; |
---|
111 | |
---|
112 | for (i = 0; i < contents.length; i++) { |
---|
113 | var skip = false; |
---|
114 | |
---|
115 | if(comments[i]){ |
---|
116 | continue; |
---|
117 | } |
---|
118 | |
---|
119 | ch = contents[i]; |
---|
120 | |
---|
121 | switch(ch){ |
---|
122 | case "\"": |
---|
123 | if(marker == DOUBLE_QUOTE) { |
---|
124 | marker = UNMARK; |
---|
125 | } else if (marker == null) { |
---|
126 | marker = DOUBLE_QUOTE; |
---|
127 | pos = i; |
---|
128 | } |
---|
129 | |
---|
130 | break; |
---|
131 | case "'": |
---|
132 | if(marker == SINGLE_QUOTE) { |
---|
133 | marker = UNMARK; |
---|
134 | } else if (marker == null) { |
---|
135 | marker = SINGLE_QUOTE; |
---|
136 | pos = i; |
---|
137 | } |
---|
138 | |
---|
139 | break; |
---|
140 | case "/": |
---|
141 | if(marker == null){ |
---|
142 | if(contents[i + 1] == "/"){ |
---|
143 | marker = LINE_COMMENT; |
---|
144 | pos = i; |
---|
145 | skip = true; |
---|
146 | } else if(contents[i + 1] == "*"){ |
---|
147 | marker = MULTI_COMMENT; |
---|
148 | pos = i; |
---|
149 | skip = true; |
---|
150 | } |
---|
151 | } |
---|
152 | |
---|
153 | break; |
---|
154 | case "*": |
---|
155 | if (marker == MULTI_COMMENT){ |
---|
156 | if(contents[i + 1] == "/"){ |
---|
157 | marker = UNMARK; |
---|
158 | skip = true; |
---|
159 | } |
---|
160 | } |
---|
161 | |
---|
162 | break; |
---|
163 | case "\n": |
---|
164 | if(marker == LINE_COMMENT){ |
---|
165 | marker = UNMARK; |
---|
166 | } |
---|
167 | break; |
---|
168 | |
---|
169 | } |
---|
170 | if (marker != null) { |
---|
171 | comments[i] = 1; |
---|
172 | } |
---|
173 | if (marker == UNMARK){ |
---|
174 | marker = null; |
---|
175 | } |
---|
176 | if (skip) { |
---|
177 | i++; |
---|
178 | comments[i] = 1; |
---|
179 | } |
---|
180 | } |
---|
181 | |
---|
182 | |
---|
183 | return comments; |
---|
184 | } |
---|
185 | |
---|
186 | // Calculate the line number of the character at index 'pos' |
---|
187 | checkstyleUtil.getLineNumber = function(contents, pos){ |
---|
188 | var counter = 0; |
---|
189 | var sep = "\n"; |
---|
190 | |
---|
191 | for(var i = pos; i > -1; i--){ |
---|
192 | if(contents.charAt(i) == "\n"){ |
---|
193 | counter ++; |
---|
194 | } |
---|
195 | } |
---|
196 | return counter + 1; |
---|
197 | }; |
---|
198 | |
---|
199 | // Store the information for a single error. |
---|
200 | checkstyleUtil.addError = function(msg, fileName, contents, pos){ |
---|
201 | while(fileName.indexOf("../") == 0){ |
---|
202 | fileName = fileName.substring(3); |
---|
203 | } |
---|
204 | checkstyleUtil.errors.push({ |
---|
205 | file: fileName, |
---|
206 | line: checkstyleUtil.getLineNumber(contents, pos), |
---|
207 | message: msg |
---|
208 | }); |
---|
209 | }; |
---|
210 | |
---|
211 | // Find the next character in 'contents' after the index 'start' |
---|
212 | // Spaces and tabs are ignored. |
---|
213 | checkstyleUtil.getNextChar = function(contents, start, comments, ignoreNewLine){ |
---|
214 | for(var i = start; i < contents.length; i++){ |
---|
215 | if(comments && comments[i]){ |
---|
216 | continue; |
---|
217 | } |
---|
218 | if(contents.charAt(i) != " " |
---|
219 | && contents.charAt(i) != "\t" |
---|
220 | && (!ignoreNewLine || contents.charCodeAt(i) != 13)){ |
---|
221 | return { |
---|
222 | value: contents[i], |
---|
223 | pos: i |
---|
224 | }; |
---|
225 | } |
---|
226 | } |
---|
227 | return null; |
---|
228 | }; |
---|
229 | |
---|
230 | // Find the next occurrence of the character in the |
---|
231 | // 'contents' array after the index 'start' |
---|
232 | checkstyleUtil.findNextCharPos = function(contents, start, character){ |
---|
233 | for(var i = start; i < contents.length; i++){ |
---|
234 | if(contents.charAt(i) == character){ |
---|
235 | return i; |
---|
236 | } |
---|
237 | } |
---|
238 | return -1; |
---|
239 | }; |
---|
240 | |
---|
241 | // Creates a simple function that searches for the token, and |
---|
242 | // adds an error if it is found |
---|
243 | checkstyleUtil.createSimpleSearch = function(token, message){ |
---|
244 | return function(fileName, contents, comments){ |
---|
245 | var idx = contents.indexOf(token); |
---|
246 | |
---|
247 | while(idx > -1){ |
---|
248 | |
---|
249 | if(!comments[idx]){ |
---|
250 | checkstyleUtil.addError(message, fileName, contents, idx); |
---|
251 | } |
---|
252 | idx = contents.indexOf(token, idx + 1); |
---|
253 | } |
---|
254 | }; |
---|
255 | }; |
---|
256 | |
---|
257 | // Creates a function that fails a test if the given token |
---|
258 | // does not have a space to the left and right. |
---|
259 | checkstyleUtil.createSpaceWrappedSearch = function(token, message){ |
---|
260 | return function(fileName, contents, comments){ |
---|
261 | |
---|
262 | var idx = contents.indexOf(token); |
---|
263 | var before, after; |
---|
264 | var tokenLength = token.length; |
---|
265 | |
---|
266 | while(idx > -1){ |
---|
267 | before = contents.charAt(idx - 1); |
---|
268 | after = contents.charAt(idx + tokenLength); |
---|
269 | if(!comments[idx] && |
---|
270 | ((before != " " && before != "\t" |
---|
271 | && (token != "==" || before != "!") |
---|
272 | && (token != "=" || |
---|
273 | (before != "<" && |
---|
274 | before != ">" && |
---|
275 | before != "=" && |
---|
276 | before != "!" && |
---|
277 | before != "+" && |
---|
278 | before != "-" && |
---|
279 | before != "*" && |
---|
280 | before != "/" && |
---|
281 | before != "&" && |
---|
282 | before != "|" ))) || |
---|
283 | ( |
---|
284 | (after != " " && contents.charCodeAt(idx + tokenLength) != 13 |
---|
285 | && contents.charCodeAt(idx + tokenLength) != 10) |
---|
286 | && (token != "==" || after != "=") |
---|
287 | && (token != "!=" || after != "=") |
---|
288 | && (token != "<" || after != "=") |
---|
289 | && (token != ">" || after != "=") |
---|
290 | && (token != "=" || after != "=") |
---|
291 | && (token != "&" || after != "=") |
---|
292 | && (token != "|" || after != "=") |
---|
293 | && (token != "+" || after != "=") |
---|
294 | && (token != "-" || after != "=") |
---|
295 | && (token != "*" || after != "=") |
---|
296 | && (token != "/" || after != "=") |
---|
297 | ))){ |
---|
298 | checkstyleUtil.addError(message, fileName, contents, idx); |
---|
299 | } |
---|
300 | idx = contents.indexOf(token, idx + token.length); |
---|
301 | } |
---|
302 | }; |
---|
303 | }; |
---|
304 | |
---|
305 | |
---|
306 | |
---|
307 | checkstyleUtil.isEOL = function(contents, pos){ |
---|
308 | var c = contents.charCodeAt(pos); |
---|
309 | return c == 10 || c == 13 || contents.charAt(pos) == "\n"; |
---|
310 | }; |
---|
311 | |
---|
312 | // All the rules that will be applied to each file. |
---|
313 | checkstyleUtil.rules = { |
---|
314 | |
---|
315 | "elseFollowedBySpace": function(fileName, contents, comments){ |
---|
316 | var idx = contents.indexOf("else "); |
---|
317 | while(idx > -1){ |
---|
318 | |
---|
319 | if(!comments[idx] && contents.substring(idx + 5, idx + 7) != "if"){ |
---|
320 | checkstyleUtil.addError("\" else \" cannot be followed by a space", fileName, contents, idx); |
---|
321 | } |
---|
322 | idx = contents.indexOf("else {", idx + 1); |
---|
323 | } |
---|
324 | }, |
---|
325 | |
---|
326 | "trailingComma" : function(fileName, contents, comments){ |
---|
327 | |
---|
328 | var s = ","; |
---|
329 | var idx = contents.indexOf(s); |
---|
330 | var nextChar; |
---|
331 | |
---|
332 | while(idx > -1){ |
---|
333 | if(!comments[idx]){ |
---|
334 | nextChar = checkstyleUtil.getNextChar(contents, idx + 1, comments, true); |
---|
335 | if(nextChar && nextChar.value == "}"){ |
---|
336 | checkstyleUtil.addError("Trailing commas are not permitted", fileName, contents, idx); |
---|
337 | } |
---|
338 | } |
---|
339 | idx = contents.indexOf(s, idx + 1); |
---|
340 | } |
---|
341 | }, |
---|
342 | |
---|
343 | "switchCaseNewLine" : function(fileName, contents, comments){ |
---|
344 | var s = "\tcase "; |
---|
345 | var idx = contents.indexOf(s); |
---|
346 | var nextColonIdx; |
---|
347 | var eolIdx; |
---|
348 | |
---|
349 | while(idx > -1){ |
---|
350 | |
---|
351 | if(!comments[idx]){ |
---|
352 | eolIdx = contents.indexOf("\n", idx + 4); |
---|
353 | |
---|
354 | if(eolIdx > idx){ |
---|
355 | // Count backwards from the end of the line. |
---|
356 | // The first character, that is not a comment, |
---|
357 | // Should be a ':' |
---|
358 | |
---|
359 | for(var i = eolIdx; i > idx + 4; i--){ |
---|
360 | var c = contents.charAt(i); |
---|
361 | if(!comments[i] |
---|
362 | && c != ' ' |
---|
363 | && c != '\t' |
---|
364 | && c != ':' |
---|
365 | && !checkstyleUtil.isEOL(contents, i)){ |
---|
366 | checkstyleUtil.addError( |
---|
367 | "A CASE statement should be followed by a new line", |
---|
368 | fileName, contents, idx); |
---|
369 | break; |
---|
370 | } |
---|
371 | if(c == ':'){ |
---|
372 | break; |
---|
373 | } |
---|
374 | } |
---|
375 | } |
---|
376 | } |
---|
377 | idx = contents.indexOf(s, idx + 4); |
---|
378 | } |
---|
379 | }, |
---|
380 | |
---|
381 | "curlyBraceAtStartOfLine": function(fileName, contents, comments){ |
---|
382 | |
---|
383 | var idx = contents.indexOf("\n"); |
---|
384 | |
---|
385 | while(idx > -1){ |
---|
386 | var nextChar = checkstyleUtil.getNextChar(contents, idx + 1); |
---|
387 | |
---|
388 | if(nextChar && !comments[nextChar.pos] && nextChar.value == "{"){ |
---|
389 | // Go back three lines, and look for "dojo.declare". If it exists in the last three lines, |
---|
390 | // then it is ok to have { at the start of this line. |
---|
391 | |
---|
392 | var nlCount = 0; |
---|
393 | var i; |
---|
394 | for(i = idx - 1; i > -1 && nlCount < 3; i--){ |
---|
395 | if(contents[i] == "\n"){ |
---|
396 | nlCount++; |
---|
397 | } |
---|
398 | } |
---|
399 | var declarePos = contents.indexOf("dojo.declare", Math.max(0, i)); |
---|
400 | if(declarePos < 0 || declarePos > idx){ |
---|
401 | checkstyleUtil.addError("An opening curly brace should not be the first on a line", fileName, contents, idx); |
---|
402 | } |
---|
403 | } |
---|
404 | idx = contents.indexOf("\n", idx + 1); |
---|
405 | } |
---|
406 | }, |
---|
407 | |
---|
408 | "parenthesisSpaceCurlyBrace": checkstyleUtil.createSimpleSearch(") {", "A space is not permitted between a closing parenthesis and a curly brace"), |
---|
409 | |
---|
410 | "useTabs": function(fileName, contents, comments){ |
---|
411 | |
---|
412 | var idx = contents.indexOf(" "); |
---|
413 | |
---|
414 | while(idx > -1){ |
---|
415 | var nextChar = checkstyleUtil.getNextChar(contents, idx + 1); |
---|
416 | if(!comments[idx] && nextChar && nextChar.value.charCodeAt(0) != 13){ |
---|
417 | checkstyleUtil.addError("Tabs should be used instead of spaces", fileName, contents, idx); |
---|
418 | var nextLine = checkstyleUtil.findNextCharPos(contents, idx + 1, "\n"); |
---|
419 | if(nextLine < 0){ |
---|
420 | break; |
---|
421 | } |
---|
422 | idx = contents.indexOf(" ", nextLine + 1); |
---|
423 | } else{ |
---|
424 | idx = contents.indexOf(" ", idx + 2); |
---|
425 | } |
---|
426 | } |
---|
427 | }, |
---|
428 | |
---|
429 | "commentFormatting": function(fileName, contents, comments){ |
---|
430 | |
---|
431 | var commentNames = checkstyleUtil.commentNames; |
---|
432 | var invalidPrefixes = ["//", "//\t"]; |
---|
433 | var idx; |
---|
434 | |
---|
435 | for(var i = 0; i < commentNames.length; i++){ |
---|
436 | var comment = commentNames[i]; |
---|
437 | |
---|
438 | for(var j = 0; j < invalidPrefixes.length; j++){ |
---|
439 | idx = contents.indexOf(invalidPrefixes[j] + comment + ":"); |
---|
440 | |
---|
441 | // Make sure that there is a space before the comment. |
---|
442 | while(idx > -1){ |
---|
443 | checkstyleUtil.addError("Must be just a space in a comment before \"" + comment + "\"" , fileName, contents, idx); |
---|
444 | var nextLine = checkstyleUtil.findNextCharPos(contents, idx + 1, "\n"); |
---|
445 | if(nextLine < 0){ |
---|
446 | break; |
---|
447 | } |
---|
448 | idx = contents.indexOf(invalidPrefixes[j] + comment + ":", nextLine); |
---|
449 | } |
---|
450 | } |
---|
451 | |
---|
452 | idx = contents.indexOf(comment + ":"); |
---|
453 | |
---|
454 | // Make sure that the comment name is on a line by itself. The body of the comment |
---|
455 | // must be on the next line. |
---|
456 | while(idx > -1){ |
---|
457 | if(comments[idx]){ |
---|
458 | var search = idx + comment.length + 1; |
---|
459 | |
---|
460 | // Make sure that there is nothing after the comment name on the same line. |
---|
461 | while(!checkstyleUtil.isEOL(contents, search)){ |
---|
462 | if(contents[search] != " " && contents[search] != "\t"){ |
---|
463 | checkstyleUtil.addError("The comment \"" + comment + "\" must be followed by a new line" , |
---|
464 | fileName, contents, idx); |
---|
465 | break; |
---|
466 | } |
---|
467 | search++; |
---|
468 | } |
---|
469 | } |
---|
470 | idx = contents.indexOf(comment + ":", idx + comment.length + 2); |
---|
471 | } |
---|
472 | } |
---|
473 | }, |
---|
474 | |
---|
475 | "spacesAroundEquals": checkstyleUtil.createSpaceWrappedSearch("==", "The equals sign should be preceded and followed by a space"), |
---|
476 | "spacesAroundNotEquals": checkstyleUtil.createSpaceWrappedSearch("!=", "The != sign should be preceded and followed by a space"), |
---|
477 | "spacesAroundAssignment": checkstyleUtil.createSpaceWrappedSearch("=", "The = sign should be preceded and followed by a space"), |
---|
478 | "spacesAroundOr": checkstyleUtil.createSpaceWrappedSearch("||", "The || sign should be preceded and followed by a space"), |
---|
479 | "spacesAroundLessThan": checkstyleUtil.createSpaceWrappedSearch("<", "The < sign should be preceded and followed by a space"), |
---|
480 | "spacesAroundGreaterThan": checkstyleUtil.createSpaceWrappedSearch(">", "The > sign should be preceded and followed by a space"), |
---|
481 | "spacesAroundAnd": checkstyleUtil.createSpaceWrappedSearch("&&", "The && sign should be preceded and followed by a space") |
---|
482 | }; |
---|
483 | |
---|
484 | var noSpaceAfter = ["catch","do","finally","for","if","switch","try","while","with"]; |
---|
485 | |
---|
486 | // Add checks for all the elements that are not allowed to have a space after them. |
---|
487 | checkstyleUtil.createNoSpaceAfterFunction = function(name){ |
---|
488 | checkstyleUtil.rules["noSpaceAfter" + noSpaceAfter[i] + "1"] = |
---|
489 | checkstyleUtil.createSimpleSearch(" " + name +" ", "\" " + name + " \" cannot be followed by a space"); |
---|
490 | checkstyleUtil.rules["noSpaceAfter" + noSpaceAfter[i] + "2"] = |
---|
491 | checkstyleUtil.createSimpleSearch("\t" + name +" ", "\" " + name + " \" cannot be followed by a space"); |
---|
492 | } |
---|
493 | |
---|
494 | for(var i = 0; i < noSpaceAfter.length; i++){ |
---|
495 | checkstyleUtil.createNoSpaceAfterFunction(noSpaceAfter[i]); |
---|
496 | } |
---|
497 | |
---|
498 | checkstyleUtil.clear = function(){ |
---|
499 | checkstyleUtil.errors = []; |
---|
500 | } |
---|
501 | |
---|
502 | checkstyleUtil.serializeErrors = function(){ |
---|
503 | var buf = []; |
---|
504 | var errs = checkstyleUtil.errors; |
---|
505 | for(var i = 0; i < errs.length; i++){ |
---|
506 | buf.push(errs[i].file + ":" + errs[i].line + " - " + errs[i].message); |
---|
507 | } |
---|
508 | return buf.join("\n"); |
---|
509 | } |
---|
510 | |
---|
511 | checkstyleUtil.makeSimpleFixes = function(contents){ |
---|
512 | |
---|
513 | var comments = checkstyleUtil.getComments(contents); |
---|
514 | for(var i = 0; i < noSpaceAfter.length; i++){ |
---|
515 | contents = checkstyleUtil.fixSpaceAfter(contents, noSpaceAfter[i], comments); |
---|
516 | } |
---|
517 | /* |
---|
518 | contents = contents.split(" ").join("\t") |
---|
519 | .split(" ").join("\t") |
---|
520 | .split(") {").join("){") |
---|
521 | .split("\tif (").join("\tif(") |
---|
522 | .split("} else").join("}else") |
---|
523 | .split("}\telse").join("}else") |
---|
524 | .split("}else {").join("}else{") |
---|
525 | .split("\twhile (").join("\twhile(") |
---|
526 | .split("\tfor (").join("\tfor(") |
---|
527 | .split("\tswitch (").join("\tswitch("); |
---|
528 | */ |
---|
529 | |
---|
530 | contents = checkstyleUtil.replaceAllExceptComments(contents, "= ", "= ", comments); |
---|
531 | comments = checkstyleUtil.getComments(contents); |
---|
532 | contents = checkstyleUtil.replaceAllExceptComments(contents, " ", "\t", comments); |
---|
533 | comments = checkstyleUtil.getComments(contents); |
---|
534 | contents = checkstyleUtil.replaceAllExceptComments(contents, " ", "\t", comments); |
---|
535 | comments = checkstyleUtil.getComments(contents); |
---|
536 | contents = checkstyleUtil.replaceAllExceptComments(contents, "\tif (", "\tif(", comments); |
---|
537 | comments = checkstyleUtil.getComments(contents); |
---|
538 | contents = checkstyleUtil.replaceAllExceptComments(contents, "} else", "}else", comments); |
---|
539 | comments = checkstyleUtil.getComments(contents); |
---|
540 | contents = checkstyleUtil.replaceAllExceptComments(contents, "}\telse", "}else", comments); |
---|
541 | comments = checkstyleUtil.getComments(contents); |
---|
542 | contents = checkstyleUtil.replaceAllExceptComments(contents, "}else {", "}else{", comments); |
---|
543 | comments = checkstyleUtil.getComments(contents); |
---|
544 | contents = checkstyleUtil.replaceAllExceptComments(contents, "\twhile (", "\twhile(", comments); |
---|
545 | comments = checkstyleUtil.getComments(contents); |
---|
546 | contents = checkstyleUtil.replaceAllExceptComments(contents, "\tfor (", "\tfor(", comments); |
---|
547 | comments = checkstyleUtil.getComments(contents); |
---|
548 | contents = checkstyleUtil.replaceAllExceptComments(contents, "\tswitch (", "\tswitch(", comments); |
---|
549 | comments = checkstyleUtil.getComments(contents); |
---|
550 | contents = checkstyleUtil.replaceAllExceptComments(contents, ") {", "){", comments); |
---|
551 | comments = checkstyleUtil.getComments(contents); |
---|
552 | contents = checkstyleUtil.replaceAllExceptComments(contents, "//summary:", "// summary:", {}); |
---|
553 | contents = checkstyleUtil.replaceAllExceptComments(contents, "//description:", "// description:", {}); |
---|
554 | comments = checkstyleUtil.getComments(contents); |
---|
555 | |
---|
556 | contents = checkstyleUtil.fixTrailingWhitespace(contents); |
---|
557 | comments = checkstyleUtil.getComments(contents); |
---|
558 | contents = checkstyleUtil.fixSpaceBeforeAndAfter(contents, "===", comments); |
---|
559 | comments = checkstyleUtil.getComments(contents); |
---|
560 | contents = checkstyleUtil.fixSpaceBeforeAndAfter(contents, "!==", comments); |
---|
561 | comments = checkstyleUtil.getComments(contents); |
---|
562 | contents = checkstyleUtil.fixSpaceBeforeAndAfter(contents, "<=", comments); |
---|
563 | comments = checkstyleUtil.getComments(contents); |
---|
564 | contents = checkstyleUtil.fixSpaceBeforeAndAfter(contents, "<", comments); |
---|
565 | comments = checkstyleUtil.getComments(contents); |
---|
566 | contents = checkstyleUtil.fixSpaceBeforeAndAfter(contents, ">=", comments); |
---|
567 | comments = checkstyleUtil.getComments(contents); |
---|
568 | contents = checkstyleUtil.fixSpaceBeforeAndAfter(contents, ">", comments); |
---|
569 | comments = checkstyleUtil.getComments(contents); |
---|
570 | contents = checkstyleUtil.fixSpaceBeforeAndAfter(contents, "!=", comments); |
---|
571 | comments = checkstyleUtil.getComments(contents); |
---|
572 | contents = checkstyleUtil.fixSpaceBeforeAndAfter(contents, "==", comments); |
---|
573 | comments = checkstyleUtil.getComments(contents); |
---|
574 | contents = checkstyleUtil.fixSpaceBeforeAndAfter(contents, "=", comments); |
---|
575 | comments = checkstyleUtil.getComments(contents); |
---|
576 | contents = checkstyleUtil.fixSpaceBeforeAndAfter(contents, "||", comments); |
---|
577 | comments = checkstyleUtil.getComments(contents); |
---|
578 | contents = checkstyleUtil.fixSpaceBeforeAndAfter(contents, "&&", comments); |
---|
579 | comments = checkstyleUtil.getComments(contents); |
---|
580 | |
---|
581 | contents = checkstyleUtil.fixCommentNames(contents); |
---|
582 | |
---|
583 | |
---|
584 | |
---|
585 | return contents; |
---|
586 | } |
---|
587 | |
---|
588 | checkstyleUtil.fixCommentNames = function(contents){ |
---|
589 | var commentNames = checkstyleUtil.commentNames; |
---|
590 | var i; |
---|
591 | |
---|
592 | for(i = 0; i < commentNames.length; i++){ |
---|
593 | contents = checkstyleUtil.replaceAllExceptComments(contents, "//\t" + commentNames[i] + ":", "// " + commentNames[i] + ":", {}); |
---|
594 | } |
---|
595 | |
---|
596 | for(i = 0; i < commentNames.length; i++){ |
---|
597 | var commentName = commentNames[i]; |
---|
598 | var searchToken = "// " + commentName + ":"; |
---|
599 | var idx = contents.indexOf(searchToken); |
---|
600 | |
---|
601 | |
---|
602 | while(idx > -1){ |
---|
603 | // If the comment name is not followed immediately by a new line, then insert a new line, |
---|
604 | // two forward slashes and two tabs. |
---|
605 | if(!checkstyleUtil.isEOL(contents, idx + commentName.length + 4)){ |
---|
606 | // Calculate how many tabs to put before the "//" |
---|
607 | |
---|
608 | var tabs = ""; |
---|
609 | var search = idx - 1; |
---|
610 | while(!checkstyleUtil.isEOL(contents, search)){ |
---|
611 | tabs += contents.charAt(search); |
---|
612 | search--; |
---|
613 | } |
---|
614 | var insertPos = idx + commentName.length + 4; |
---|
615 | if(contents.charAt(insertPos) == " " || contents.charAt(insertPos) == "\t"){ |
---|
616 | contents = checkstyleUtil.deleteChar(contents, insertPos); |
---|
617 | } |
---|
618 | |
---|
619 | contents = checkstyleUtil.insertChar(contents, "\n" + tabs + "//\t\t", idx + commentName.length + 4); |
---|
620 | |
---|
621 | } |
---|
622 | idx = contents.indexOf(searchToken, idx + commentName.length); |
---|
623 | } |
---|
624 | } |
---|
625 | return contents; |
---|
626 | } |
---|
627 | |
---|
628 | |
---|
629 | checkstyleUtil.replaceAllExceptComments = function(contents, old, newStr, comments){ |
---|
630 | var idx = contents.indexOf(old); |
---|
631 | var toRemove = []; |
---|
632 | |
---|
633 | while(idx > -1){ |
---|
634 | if(!comments[idx]){ |
---|
635 | toRemove.push(idx); |
---|
636 | } |
---|
637 | |
---|
638 | idx = contents.indexOf(old, idx + old.length); |
---|
639 | } |
---|
640 | |
---|
641 | // Process the string backwards so we don't have to recompute the comments each time. |
---|
642 | for(var i = toRemove.length - 1; i > -1; i--){ |
---|
643 | idx = toRemove[i]; |
---|
644 | if(!comments[idx]){ |
---|
645 | contents = contents.substring(0, idx) |
---|
646 | + newStr |
---|
647 | + contents.substring(idx + old.length, contents.length); |
---|
648 | } |
---|
649 | } |
---|
650 | return contents; |
---|
651 | } |
---|
652 | |
---|
653 | checkstyleUtil.insertChar = function(contents, ch, pos){ |
---|
654 | return contents.substring(0, pos) + ch + contents.substring(pos); |
---|
655 | } |
---|
656 | checkstyleUtil.deleteChar = function(contents, pos){ |
---|
657 | return contents.substring(0, pos) + contents.substring(pos + 1); |
---|
658 | } |
---|
659 | |
---|
660 | checkstyleUtil.fixTrailingWhitespace = function(contents) { |
---|
661 | var idx = contents.indexOf("\n"); |
---|
662 | |
---|
663 | // Find each new line character, then iterate backwards until a non-whitespace character is found |
---|
664 | // then remove the whitespace. |
---|
665 | while(idx > -1){ |
---|
666 | var search = idx - 1; |
---|
667 | |
---|
668 | while(search > -1 && (contents.charAt(search) == " " || contents.charAt(search) == "\t")){ |
---|
669 | search--; |
---|
670 | } |
---|
671 | |
---|
672 | if(search < idx -1){ |
---|
673 | contents = contents.substring(0, search + 1) |
---|
674 | + contents.substring(idx, contents.length); |
---|
675 | |
---|
676 | idx = contents.indexOf("\n", search + 2); |
---|
677 | }else{ |
---|
678 | idx = contents.indexOf("\n", idx + 1); |
---|
679 | } |
---|
680 | } |
---|
681 | |
---|
682 | return contents; |
---|
683 | } |
---|
684 | |
---|
685 | checkstyleUtil.fixSpaceAfter = function(contents, token, comments){ |
---|
686 | var idx = contents.indexOf(token + " "); |
---|
687 | |
---|
688 | while(idx > -1){ |
---|
689 | if(!comments[idx]){ |
---|
690 | contents = checkstyleUtil.deleteChar(contents, idx + token.length); |
---|
691 | } |
---|
692 | |
---|
693 | idx = contents.indexOf(token + " ", idx + token.length); |
---|
694 | } |
---|
695 | return contents; |
---|
696 | } |
---|
697 | |
---|
698 | checkstyleUtil.fixSpaceBeforeAndAfter = function(contents, token, comments){ |
---|
699 | var idx = contents.indexOf(token); |
---|
700 | var before, after; |
---|
701 | var len = token.length; |
---|
702 | |
---|
703 | while(idx > -1){ |
---|
704 | before = contents.charAt(idx - 1); |
---|
705 | after = contents.charAt(idx + len); |
---|
706 | if(!comments[idx]){ |
---|
707 | // Only insert a space before the token if: |
---|
708 | // - char before is not a space or a tab |
---|
709 | // - token is "==" and the char before is neither "!" or "=" |
---|
710 | |
---|
711 | if(before != " " && before != "\t" |
---|
712 | && (token != "==" || (before != "!" && before != "=")) |
---|
713 | && (token != "=" || |
---|
714 | (before != "<" && |
---|
715 | before != ">" && |
---|
716 | before != "=" && |
---|
717 | before != "!" && |
---|
718 | before != "+" && |
---|
719 | before != "-" && |
---|
720 | before != "*" && |
---|
721 | before != "/" && |
---|
722 | before != "&" && |
---|
723 | before != "|" )) |
---|
724 | ){ |
---|
725 | |
---|
726 | contents = checkstyleUtil.insertChar(contents, " ", idx); |
---|
727 | idx ++; |
---|
728 | } |
---|
729 | |
---|
730 | // Only insert a space after the token if: |
---|
731 | // - char after is not a space |
---|
732 | // - char after is not a new line |
---|
733 | // - char after is not "=" |
---|
734 | if((after != " " && contents.charCodeAt(idx + len) != 13 |
---|
735 | && contents.charCodeAt(idx + len) != 10) |
---|
736 | && (token != "==" || after != "=") |
---|
737 | && (token != "!=" || after != "=") |
---|
738 | && (token != "=" || after != "=") |
---|
739 | && (token != "<" || after != "=") |
---|
740 | && (token != ">" || after != "=") |
---|
741 | && (token != "&" || after != "=") |
---|
742 | && (token != "|" || after != "=") |
---|
743 | && (token != "+" || after != "=") |
---|
744 | && (token != "-" || after != "=") |
---|
745 | && (token != "*" || after != "=") |
---|
746 | && (token != "/" || after != "=") |
---|
747 | |
---|
748 | ){ |
---|
749 | contents = contents = checkstyleUtil.insertChar(contents, " ", idx + token.length); |
---|
750 | idx++; |
---|
751 | } |
---|
752 | } |
---|
753 | idx = contents.indexOf(token, idx + token.length); |
---|
754 | } |
---|
755 | return contents; |
---|
756 | } |
---|
757 | |
---|
758 | // Creates the data file suitable to be loaded into a dojo.data.ItemFileReadStore |
---|
759 | checkstyleUtil.generateReport = function(skipPrint){ |
---|
760 | |
---|
761 | var ids = 1; |
---|
762 | var json = ["{id:'" +(ids++) + "', file: 'All', isFolder:true}"]; |
---|
763 | |
---|
764 | // A map of folders that have already been found. |
---|
765 | var allFolders = {}; |
---|
766 | |
---|
767 | var messageIds = {}; |
---|
768 | var messageCounter = 1; |
---|
769 | var i, err; |
---|
770 | |
---|
771 | function getFolderName(fileName){ |
---|
772 | // Extract the folder name from a file name |
---|
773 | var idx = fileName.lastIndexOf("/"); |
---|
774 | return fileName.substring(0, idx); |
---|
775 | } |
---|
776 | |
---|
777 | // Add a folder to the list of folders. |
---|
778 | function pushFolder(folderName){ |
---|
779 | if(!allFolders[folderName]){ |
---|
780 | allFolders[folderName] = true; |
---|
781 | json.push("{id: '" +(ids++) + "', file: '" + folderName + "', folder: 1}"); |
---|
782 | } |
---|
783 | } |
---|
784 | |
---|
785 | for(i = 0; i < checkstyleUtil.errors.length; i++){ |
---|
786 | err = checkstyleUtil.errors[i]; |
---|
787 | var message = err.message; |
---|
788 | var messageId = messageIds[message]; |
---|
789 | if(!messageId){ |
---|
790 | messageId = "m" + messageCounter++; |
---|
791 | messageIds[message] = messageId; |
---|
792 | |
---|
793 | json.push("{id:'" + messageId + |
---|
794 | "',msg:'" + message + |
---|
795 | "'}"); |
---|
796 | } |
---|
797 | } |
---|
798 | |
---|
799 | pushFolder("All"); |
---|
800 | |
---|
801 | // Create the JSON records for each error. |
---|
802 | for(i = 0; i < checkstyleUtil.errors.length; i++){ |
---|
803 | err = checkstyleUtil.errors[i]; |
---|
804 | var folderName = getFolderName(err.file); |
---|
805 | pushFolder(folderName); |
---|
806 | |
---|
807 | json.push("{id:'" +(ids++) + |
---|
808 | "', file:'" + err.file + |
---|
809 | "',line:" + err.line + |
---|
810 | ",msg:{'_reference':'" + messageIds[err.message] + |
---|
811 | //"'},folder:'" + folderName + |
---|
812 | "'},folder: 0" + |
---|
813 | "}"); |
---|
814 | |
---|
815 | } |
---|
816 | |
---|
817 | // Add the date that the check was run to the store. |
---|
818 | json.push("{id:'" +(ids++) + "', date: " +(new Date()).getTime() + "}"); |
---|
819 | |
---|
820 | // Save the file. |
---|
821 | |
---|
822 | if(!skipPrint){ |
---|
823 | print("Found " + checkstyleUtil.errors.length + " checkstyle errors. " + |
---|
824 | "Open the file checkstyleReport.html to view the results."); |
---|
825 | } |
---|
826 | |
---|
827 | return "{ identifier: 'id', label:'file', items: [" + json.join(",\n") + "]}"; |
---|
828 | }; |
---|