[483] | 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 | }; |
---|