No Description

jshint.js 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*
  2. * grunt-contrib-jshint
  3. * http://gruntjs.com/
  4. *
  5. * Copyright (c) 2013 "Cowboy" Ben Alman, contributors
  6. * Licensed under the MIT license.
  7. */
  8. 'use strict';
  9. var path = require('path');
  10. var jshint = require('jshint').JSHINT;
  11. var jshintcli = require('jshint/src/cli');
  12. exports.init = function(grunt) {
  13. var exports = {
  14. usingGruntReporter: false
  15. };
  16. var pad = function(msg,length) {
  17. while (msg.length < length) {
  18. msg = ' ' + msg;
  19. }
  20. return msg;
  21. };
  22. // Select a reporter (if not using the default Grunt reporter)
  23. // Copied from jshint/src/cli/cli.js until that part is exposed
  24. exports.selectReporter = function(options) {
  25. switch (true) {
  26. // JSLint reporter
  27. case options.reporter === 'jslint':
  28. case options['jslint-reporter']:
  29. options.reporter = 'jshint/src/reporters/jslint_xml.js';
  30. break;
  31. // CheckStyle (XML) reporter
  32. case options.reporter === 'checkstyle':
  33. case options['checkstyle-reporter']:
  34. options.reporter = 'jshint/src/reporters/checkstyle.js';
  35. break;
  36. // Reporter that displays additional JSHint data
  37. case options['show-non-errors']:
  38. options.reporter = 'jshint/src/reporters/non_error.js';
  39. break;
  40. // Custom reporter
  41. case options.reporter !== undefined:
  42. options.reporter = path.resolve(process.cwd(), options.reporter);
  43. }
  44. var reporter;
  45. if (options.reporter) {
  46. try {
  47. reporter = require(options.reporter).reporter;
  48. exports.usingGruntReporter = false;
  49. } catch (err) {
  50. grunt.fatal(err);
  51. }
  52. }
  53. // Use the default Grunt reporter if none are found
  54. if (!reporter) {
  55. reporter = exports.reporter;
  56. exports.usingGruntReporter = true;
  57. }
  58. return reporter;
  59. };
  60. // Default Grunt JSHint reporter
  61. exports.reporter = function(results, data) {
  62. // Dont report empty data as its an ignored file
  63. if (data.length < 1) {
  64. grunt.log.error('0 files linted. Please check your ignored files.');
  65. return;
  66. }
  67. if (results.length === 0) {
  68. // Success!
  69. grunt.verbose.ok();
  70. return;
  71. }
  72. var options = data[0].options;
  73. grunt.log.writeln();
  74. var lastfile = null;
  75. // Iterate over all errors.
  76. results.forEach(function(result) {
  77. // Only print file name once per error
  78. if (result.file !== lastfile) {
  79. grunt.log.writeln((result.file ? ' ' + result.file : '').bold);
  80. }
  81. lastfile = result.file;
  82. var e = result.error;
  83. // Sometimes there's no error object.
  84. if (!e) { return; }
  85. if (e.evidence) {
  86. // Manually increment errorcount since we're not using grunt.log.error().
  87. grunt.fail.errorcount++;
  88. // No idea why JSHint treats tabs as options.indent # characters wide, but it
  89. // does. See issue: https://github.com/jshint/jshint/issues/430
  90. // Replacing tabs with appropriate spaces (i.e. columns) ensures that
  91. // caret will line up correctly.
  92. var evidence = e.evidence.replace(/\t/g,grunt.util.repeat(options.indent,' '));
  93. grunt.log.writeln((pad(e.line.toString(),7) + ' |') + evidence.grey);
  94. grunt.log.write(grunt.util.repeat(9,' ') + grunt.util.repeat(e.character -1,' ') + '^ ');
  95. grunt.verbose.write('[' + e.code + '] ');
  96. grunt.log.writeln(e.reason);
  97. } else {
  98. // Generic "Whoops, too many errors" error.
  99. grunt.log.error(e.reason);
  100. }
  101. });
  102. grunt.log.writeln();
  103. };
  104. // Run JSHint on the given files with the given options
  105. exports.lint = function(files, options, done) {
  106. var cliOptions = {
  107. verbose: grunt.option('verbose'),
  108. extensions: '',
  109. };
  110. // A list of non-dot-js extensions to check
  111. if (options.extensions) {
  112. cliOptions.extensions = options.extensions;
  113. delete options.extensions;
  114. }
  115. // A list ignored files
  116. if (options.ignores) {
  117. if (typeof options.ignores === 'string') {
  118. options.ignores = [options.ignores];
  119. }
  120. cliOptions.ignores = options.ignores;
  121. delete options.ignores;
  122. }
  123. // Option to extract JS from HTML file
  124. if (options.extract) {
  125. cliOptions.extract = options.extract;
  126. delete options.extract;
  127. }
  128. // Get reporter output directory for relative paths in reporters
  129. if (options.hasOwnProperty('reporterOutput')) {
  130. var reporterOutputDir = path.dirname(options.reporterOutput);
  131. delete options.reporterOutput;
  132. }
  133. // Select a reporter to use
  134. var reporter = exports.selectReporter(options);
  135. // Remove bad options that may have came in from the cli
  136. ['reporter', 'jslint-reporter', 'checkstyle-reporter', 'show-non-errors'].forEach(function(opt) {
  137. if (options.hasOwnProperty(opt)) {
  138. delete options[opt];
  139. }
  140. });
  141. if (options.jshintrc === true) {
  142. // let jshint find the options itself
  143. delete cliOptions.config;
  144. } else if (options.jshintrc) {
  145. // Read JSHint options from a specified jshintrc file.
  146. cliOptions.config = jshintcli.loadConfig(options.jshintrc);
  147. } else {
  148. // Enable/disable debugging if option explicitly set.
  149. if (grunt.option('debug') !== undefined) {
  150. options.devel = options.debug = grunt.option('debug');
  151. // Tweak a few things.
  152. if (grunt.option('debug')) {
  153. options.maxerr = Infinity;
  154. }
  155. }
  156. // pass all of the remaining options directly to jshint
  157. cliOptions.config = options;
  158. }
  159. // Run JSHint on all file and collect results/data
  160. var allResults = [];
  161. var allData = [];
  162. cliOptions.args = files;
  163. cliOptions.reporter = function(results, data) {
  164. results.forEach(function(datum) {
  165. datum.file = reporterOutputDir ? path.relative(reporterOutputDir, datum.file) : datum.file;
  166. });
  167. reporter(results, data, options);
  168. allResults = allResults.concat(results);
  169. allData = allData.concat(data);
  170. };
  171. jshintcli.run(cliOptions);
  172. done(allResults, allData);
  173. };
  174. return exports;
  175. };