jshint.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. /*
  2. * grunt-contrib-jshint
  3. * http://gruntjs.com/
  4. *
  5. * Copyright (c) 2012 "Cowboy" Ben Alman, contributors
  6. * Licensed under the MIT license.
  7. */
  8. 'use strict';
  9. // External libs.
  10. var jshint = require('jshint').JSHINT;
  11. exports.init = function(grunt) {
  12. var exports = {};
  13. // No idea why JSHint treats tabs as options.indent # characters wide, but it
  14. // does. See issue: https://github.com/jshint/jshint/issues/430
  15. var getTabStr = function(options) {
  16. // Do something that's going to error.
  17. jshint('\tx', options || {});
  18. // If an error occurred, figure out what character JSHint reported and
  19. // subtract one.
  20. var character = jshint.errors && jshint.errors[0] && jshint.errors[0].character - 1;
  21. // If character is actually a number, use it. Otherwise use 1.
  22. var tabsize = isNaN(character) ? 1 : character;
  23. // If tabsize > 1, return something that should be safe to use as a
  24. // placeholder. \uFFFF repeated 2+ times.
  25. return tabsize > 1 && grunt.util.repeat(tabsize, '\uFFFF');
  26. };
  27. var tabregex = /\t/g;
  28. // Lint source code with JSHint.
  29. exports.lint = function(src, options, globals, extraMsg) {
  30. // JSHint sometimes modifies objects you pass in, so clone them.
  31. options = options ? grunt.util._.clone(options) : {};
  32. globals = globals ? grunt.util._.clone(globals) : {};
  33. // Enable/disable debugging if option explicitly set.
  34. if (grunt.option('debug') !== undefined) {
  35. options.devel = options.debug = grunt.option('debug');
  36. // Tweak a few things.
  37. if (grunt.option('debug')) {
  38. options.maxerr = Infinity;
  39. }
  40. }
  41. var msg = 'Linting' + (extraMsg ? ' ' + extraMsg : '') + '...';
  42. grunt.verbose.write(msg);
  43. // Tab size as reported by JSHint.
  44. var tabstr = getTabStr(options);
  45. var placeholderregex = new RegExp(tabstr, 'g');
  46. // Lint.
  47. var result = jshint(src, options || {}, globals || {});
  48. // Attempt to work around JSHint erroneously reporting bugs.
  49. // if (!result) {
  50. // // Filter out errors that shouldn't be reported.
  51. // jshint.errors = jshint.errors.filter(function(o) {
  52. // return o && o.something === 'something';
  53. // });
  54. // // If no errors are left, JSHint actually succeeded.
  55. // result = jshint.errors.length === 0;
  56. // }
  57. if (result) {
  58. // Success!
  59. grunt.verbose.ok();
  60. return;
  61. }
  62. // Something went wrong.
  63. grunt.verbose.or.write(msg);
  64. grunt.log.error();
  65. // Iterate over all errors.
  66. jshint.errors.forEach(function(e) {
  67. // Sometimes there's no error object.
  68. if (!e) { return; }
  69. var pos;
  70. var evidence = e.evidence;
  71. var character = e.character;
  72. if (evidence) {
  73. // Manually increment errorcount since we're not using grunt.log.error().
  74. grunt.fail.errorcount++;
  75. // Descriptive code error.
  76. pos = '['.red + ('L' + e.line).yellow + ':'.red + ('C' + character).yellow + ']'.red;
  77. grunt.log.writeln(pos + ' ' + e.reason.yellow);
  78. // If necessary, eplace each tab char with something that can be
  79. // swapped out later.
  80. if (tabstr) {
  81. evidence = evidence.replace(tabregex, tabstr);
  82. }
  83. if (character === 0) {
  84. // Beginning of line.
  85. evidence = '?'.inverse.red + evidence;
  86. } else if (character > evidence.length) {
  87. // End of line.
  88. evidence = evidence + ' '.inverse.red;
  89. } else {
  90. // Middle of line.
  91. evidence = evidence.slice(0, character - 1) + evidence[character - 1].inverse.red +
  92. evidence.slice(character);
  93. }
  94. // Replace tab placeholder (or tabs) but with a 2-space soft tab.
  95. evidence = evidence.replace(tabstr ? placeholderregex : tabregex, ' ');
  96. grunt.log.writeln(evidence);
  97. } else {
  98. // Generic "Whoops, too many errors" error.
  99. grunt.log.error(e.reason);
  100. }
  101. });
  102. grunt.log.writeln();
  103. };
  104. return exports;
  105. };